Annotation of embedaddon/miniupnpd/pf/obsdrdr.c, revision 1.1.1.2

1.1.1.2 ! misho       1: /* $Id: obsdrdr.c,v 1.67 2011/06/22 21:20:27 nanard Exp $ */
1.1       misho       2: /* MiniUPnP project
                      3:  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
                      4:  * (c) 2006-2010 Thomas Bernard 
                      5:  * This software is subject to the conditions detailed
                      6:  * in the LICENCE file provided within the distribution */
                      7: 
                      8: /*
                      9:  * pf rules created (with ext_if = xl1)
                     10:  * - OpenBSD up to version 4.6 :
                     11:  *     rdr pass on xl1 inet proto udp from any to any port = 54321 \
                     12:  *            label "test label" -> 192.168.0.141 port 12345
                     13:  *   or a rdr rule + a pass rule
                     14:  *
                     15:  * - OpenBSD starting from version 4.7
                     16:  *     match in on xl1 inet proto udp from any to any port 54321 \
                     17:  *            label "test label" rdr-to 192.168.0.141 port 12345
                     18:  *   or
                     19:  *     pass in quick on xl1 inet proto udp from any to any port 54321 \
                     20:  *            label "test label" rdr-to 192.168.0.141 port 12345
                     21:  *
                     22:  *
                     23:  *
                     24:  * Macros/#defines :
                     25:  * - PF_ENABLE_FILTER_RULES
                     26:  *   If set, two rules are created : rdr + pass. Else a rdr/pass rule
                     27:  *   is created.
                     28:  * - USE_IFNAME_IN_RULES
                     29:  *   If set the interface name is set in the rule.
                     30:  * - PFRULE_INOUT_COUNTS
                     31:  *   Must be set with OpenBSD version 3.8 and up.
                     32:  * - PFRULE_HAS_RTABLEID
                     33:  *   Must be set with OpenBSD version 4.0 and up.
                     34:  * - PF_NEWSSTYLE
                     35:  *   Must be set with OpenBSD version 4.7 and up.
                     36:  */
                     37: 
                     38: #include <sys/types.h>
                     39: #include <sys/socket.h>
                     40: #include <sys/param.h>
                     41: #include <net/if.h>
                     42: #include <netinet/in.h>
                     43: #include <netinet/tcp.h>
                     44: #include <arpa/inet.h>
                     45: #ifdef __DragonFly__
                     46: #include <net/pf/pfvar.h>
                     47: #else
                     48: #include <net/pfvar.h>
                     49: #endif
                     50: #include <fcntl.h>
                     51: #include <sys/ioctl.h>
                     52: #include <unistd.h>
                     53: #include <string.h>
                     54: #include <syslog.h>
                     55: #include <stdio.h>
                     56: #include <stdlib.h>
                     57: 
                     58: #include "../config.h"
                     59: #include "obsdrdr.h"
                     60: #include "../upnpglobalvars.h"
                     61: 
1.1.1.2 ! misho      62: /* list too keep timestamps for port mappings having a lease duration */
        !            63: struct timestamp_entry {
        !            64:        struct timestamp_entry * next;
        !            65:        unsigned int timestamp;
        !            66:        unsigned short eport;
        !            67:        short protocol;
        !            68: };
        !            69: 
        !            70: static struct timestamp_entry * timestamp_list = NULL;
        !            71: 
        !            72: static unsigned int
        !            73: get_timestamp(unsigned short eport, int proto)
        !            74: {
        !            75:        struct timestamp_entry * e;
        !            76:        e = timestamp_list;
        !            77:        while(e) {
        !            78:                if(e->eport == eport && e->protocol == (short)proto)
        !            79:                        return e->timestamp;
        !            80:                e = e->next;
        !            81:        }
        !            82:        return 0;
        !            83: }
        !            84: 
        !            85: static void
        !            86: remove_timestamp_entry(unsigned short eport, int proto)
        !            87: {
        !            88:        struct timestamp_entry * e;
        !            89:        struct timestamp_entry * * p;
        !            90:        p = &timestamp_list;
        !            91:        e = *p;
        !            92:        while(e) {
        !            93:                if(e->eport == eport && e->protocol == (short)proto) {
        !            94:                        /* remove the entry */
        !            95:                        *p = e->next;
        !            96:                        free(e);
        !            97:                        return;
        !            98:                }
        !            99:                p = &(e->next);
        !           100:                e = *p;
        !           101:        }
        !           102: }
        !           103: 
1.1       misho     104: /* anchor name */
                    105: static const char anchor_name[] = "miniupnpd";
                    106: 
                    107: /* /dev/pf when opened */
                    108: static int dev = -1;
                    109: 
                    110: /* shutdown_redirect() :
                    111:  * close the /dev/pf device */
                    112: void
                    113: shutdown_redirect(void)
                    114: {
                    115:        if(close(dev)<0)
                    116:                syslog(LOG_ERR, "close(\"/dev/pf\"): %m");
                    117:        dev = -1;
                    118: }
                    119: 
                    120: /* open the device */
                    121: int
                    122: init_redirect(void)
                    123: {
                    124:        struct pf_status status;
                    125:        if(dev>=0)
                    126:                shutdown_redirect();
                    127:        dev = open("/dev/pf", O_RDWR);
                    128:        if(dev<0) {
                    129:                syslog(LOG_ERR, "open(\"/dev/pf\"): %m");
                    130:                return -1;
                    131:        }
                    132:        if(ioctl(dev, DIOCGETSTATUS, &status)<0) {
                    133:                syslog(LOG_ERR, "DIOCGETSTATUS: %m");
                    134:                return -1;
                    135:        }
                    136:        if(!status.running) {
                    137:                syslog(LOG_ERR, "pf is disabled");
                    138:                return -1;
                    139:        }
                    140:        return 0;
                    141: }
                    142: 
                    143: #if TEST
                    144: /* for debug */
                    145: int
                    146: clear_redirect_rules(void)
                    147: {
                    148:        struct pfioc_trans io;
                    149:        struct pfioc_trans_e ioe;
                    150:        if(dev<0) {
                    151:                syslog(LOG_ERR, "pf device is not open");
                    152:                return -1;
                    153:        }
                    154:        memset(&ioe, 0, sizeof(ioe));
                    155:        io.size = 1;
                    156:        io.esize = sizeof(ioe);
                    157:        io.array = &ioe;
                    158: #ifndef PF_NEWSTYLE
                    159:        ioe.rs_num = PF_RULESET_RDR;
                    160: #else
                    161:        ioe.type = PF_TRANS_RULESET;
                    162: #endif
                    163:        strlcpy(ioe.anchor, anchor_name, MAXPATHLEN);
                    164:        if(ioctl(dev, DIOCXBEGIN, &io) < 0)
                    165:        {
                    166:                syslog(LOG_ERR, "ioctl(dev, DIOCXBEGIN, ...): %m");
                    167:                goto error;
                    168:        }
                    169:        if(ioctl(dev, DIOCXCOMMIT, &io) < 0)
                    170:        {
                    171:                syslog(LOG_ERR, "ioctl(dev, DIOCXCOMMIT, ...): %m");
                    172:                goto error;
                    173:        }
                    174:        return 0;
                    175: error:
                    176:        return -1;
                    177: }
                    178: #endif
                    179: 
                    180: /* add_redirect_rule2() :
                    181:  * create a rdr rule */
                    182: int
1.1.1.2 ! misho     183: add_redirect_rule2(const char * ifname,
        !           184:                    const char * rhost, unsigned short eport,
1.1       misho     185:                    const char * iaddr, unsigned short iport, int proto,
1.1.1.2 ! misho     186:                    const char * desc, unsigned int timestamp)
1.1       misho     187: {
                    188:        int r;
                    189:        struct pfioc_rule pcr;
                    190: #ifndef PF_NEWSTYLE
                    191:        struct pfioc_pooladdr pp;
                    192:        struct pf_pooladdr *a;
                    193: #endif
                    194:        if(dev<0) {
                    195:                syslog(LOG_ERR, "pf device is not open");
                    196:                return -1;
                    197:        }
                    198:        r = 0;
                    199:        memset(&pcr, 0, sizeof(pcr));
                    200:        strlcpy(pcr.anchor, anchor_name, MAXPATHLEN);
                    201: 
                    202: #ifndef PF_NEWSTYLE
                    203:        memset(&pp, 0, sizeof(pp));
                    204:        strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
                    205:        if(ioctl(dev, DIOCBEGINADDRS, &pp) < 0)
                    206:        {
                    207:                syslog(LOG_ERR, "ioctl(dev, DIOCBEGINADDRS, ...): %m");
                    208:                r = -1;
                    209:        }
                    210:        else
                    211:        {
                    212:                pcr.pool_ticket = pp.ticket;
                    213: #else
                    214:        if(1)
                    215:        {
                    216:                pcr.rule.direction = PF_IN;
                    217:                //pcr.rule.src.addr.type = PF_ADDR_NONE;
                    218:                pcr.rule.src.addr.type = PF_ADDR_ADDRMASK;
                    219:                pcr.rule.dst.addr.type = PF_ADDR_ADDRMASK;
                    220:                pcr.rule.nat.addr.type = PF_ADDR_NONE;
                    221:                pcr.rule.rdr.addr.type = PF_ADDR_ADDRMASK;
                    222: #endif
                    223:                
                    224:                pcr.rule.dst.port_op = PF_OP_EQ;
                    225:                pcr.rule.dst.port[0] = htons(eport);
                    226:                pcr.rule.dst.port[1] = htons(eport);
                    227: #ifndef PF_NEWSTYLE
                    228:                pcr.rule.action = PF_RDR;
                    229: #ifndef PF_ENABLE_FILTER_RULES
                    230:                pcr.rule.natpass = 1;
                    231: #else
                    232:                pcr.rule.natpass = 0;
                    233: #endif
                    234: #else
                    235: #ifndef PF_ENABLE_FILTER_RULES
                    236:                pcr.rule.action = PF_PASS;
                    237: #else
                    238:                pcr.rule.action = PF_MATCH;
                    239: #endif
                    240: #endif
                    241:                pcr.rule.af = AF_INET;
                    242: #ifdef USE_IFNAME_IN_RULES
                    243:                if(ifname)
                    244:                        strlcpy(pcr.rule.ifname, ifname, IFNAMSIZ);
                    245: #endif
                    246:                pcr.rule.proto = proto;
                    247:                pcr.rule.log = (GETFLAG(LOGPACKETSMASK))?1:0;   /*logpackets;*/
                    248: #ifdef PFRULE_HAS_RTABLEID
                    249:                pcr.rule.rtableid = -1; /* first appeared in OpenBSD 4.0 */
                    250: #endif
                    251:                pcr.rule.quick = 1;
                    252:                pcr.rule.keep_state = PF_STATE_NORMAL;
                    253:                if(tag)
                    254:                        strlcpy(pcr.rule.tagname, tag, PF_TAG_NAME_SIZE);
                    255:                strlcpy(pcr.rule.label, desc, PF_RULE_LABEL_SIZE);
1.1.1.2 ! misho     256:                if(rhost && rhost[0] != '\0' && rhost[0] != '*')
        !           257:                {
        !           258:                        inet_pton(AF_INET, rhost, &pcr.rule.src.addr.v.a.addr.v4.s_addr);
        !           259:                        pcr.rule.src.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
        !           260:                }
1.1       misho     261: #ifndef PF_NEWSTYLE
                    262:                pcr.rule.rpool.proxy_port[0] = iport;
                    263:                pcr.rule.rpool.proxy_port[1] = iport;
                    264:                TAILQ_INIT(&pcr.rule.rpool.list);
                    265:                a = calloc(1, sizeof(struct pf_pooladdr));
                    266:                inet_pton(AF_INET, iaddr, &a->addr.v.a.addr.v4.s_addr);
                    267:                a->addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
                    268:                TAILQ_INSERT_TAIL(&pcr.rule.rpool.list, a, entries);
                    269: 
                    270:                memcpy(&pp.addr, a, sizeof(struct pf_pooladdr));
                    271:                if(ioctl(dev, DIOCADDADDR, &pp) < 0)
                    272:                {
                    273:                        syslog(LOG_ERR, "ioctl(dev, DIOCADDADDR, ...): %m");
                    274:                        r = -1;
                    275:                }
                    276:                else
                    277:                {
                    278: #else
                    279:                pcr.rule.rdr.proxy_port[0] = iport;
                    280:                pcr.rule.rdr.proxy_port[1] = iport;
                    281:                inet_pton(AF_INET, iaddr, &pcr.rule.rdr.addr.v.a.addr.v4.s_addr);
                    282:                pcr.rule.rdr.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
                    283:                if(1)
                    284:                {
                    285: #endif
                    286:                        pcr.action = PF_CHANGE_GET_TICKET;
                    287:                if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
                    288:                        {
                    289:                syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
                    290:                                r = -1;
                    291:                        }
                    292:                        else
                    293:                        {
                    294:                                pcr.action = PF_CHANGE_ADD_TAIL;
                    295:                                if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
                    296:                                {
                    297:                                        syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_ADD_TAIL: %m");
                    298:                                        r = -1;
                    299:                                }
                    300:                        }
                    301:                }
                    302: #ifndef PF_NEWSTYLE
                    303:                free(a);
                    304: #endif
                    305:        }
1.1.1.2 ! misho     306:        if(r == 0 && timestamp > 0)
        !           307:        {
        !           308:                struct timestamp_entry * tmp;
        !           309:                tmp = malloc(sizeof(struct timestamp_entry));
        !           310:                if(tmp)
        !           311:                {
        !           312:                        tmp->next = timestamp_list;
        !           313:                        tmp->timestamp = timestamp;
        !           314:                        tmp->eport = eport;
        !           315:                        tmp->protocol = (short)proto;
        !           316:                        timestamp_list = tmp;
        !           317:                }
        !           318:        }
1.1       misho     319:        return r;
                    320: }
                    321: 
                    322: /* thanks to Seth Mos for this function */
                    323: int
1.1.1.2 ! misho     324: add_filter_rule2(const char * ifname,
        !           325:                  const char * rhost, const char * iaddr,
1.1       misho     326:                  unsigned short eport, unsigned short iport,
                    327:                                 int proto, const char * desc)
                    328: {
                    329: #ifndef PF_ENABLE_FILTER_RULES
                    330:        return 0;
                    331: #else
                    332:        int r;
                    333:        struct pfioc_rule pcr;
                    334: #ifndef PF_NEWSTYLE
                    335:        struct pfioc_pooladdr pp;
                    336:        struct pf_pooladdr *a;
                    337: #endif
                    338:        if(dev<0) {
                    339:                syslog(LOG_ERR, "pf device is not open");
                    340:                return -1;
                    341:        }
                    342:        r = 0;
                    343:        memset(&pcr, 0, sizeof(pcr));
                    344:        strlcpy(pcr.anchor, anchor_name, MAXPATHLEN);
                    345: 
                    346: #ifndef PF_NEWSTYLE
                    347:        memset(&pp, 0, sizeof(pp));
                    348:        strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
                    349:        if(ioctl(dev, DIOCBEGINADDRS, &pp) < 0)
                    350:        {
                    351:                syslog(LOG_ERR, "ioctl(dev, DIOCBEGINADDRS, ...): %m");
                    352:                r = -1;
                    353:        }
                    354:        else
                    355:        {
                    356:                pcr.pool_ticket = pp.ticket;
                    357: #else
                    358:        if(1)
                    359:        {
                    360: #endif
                    361:                
                    362:                pcr.rule.dst.port_op = PF_OP_EQ;
                    363:                pcr.rule.dst.port[0] = htons(eport);
                    364:                pcr.rule.direction = PF_IN;
                    365:                pcr.rule.action = PF_PASS;
                    366:                pcr.rule.af = AF_INET;
                    367: #ifdef USE_IFNAME_IN_RULES
                    368:                if(ifname)
                    369:                        strlcpy(pcr.rule.ifname, ifname, IFNAMSIZ);
                    370: #endif
                    371:                pcr.rule.proto = proto;
                    372:                pcr.rule.quick = (GETFLAG(PFNOQUICKRULESMASK))?0:1;
                    373:                pcr.rule.log = (GETFLAG(LOGPACKETSMASK))?1:0;   /*logpackets;*/
                    374: /* see the discussion on the forum :
                    375:  * http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=638 */
                    376:                pcr.rule.flags = TH_SYN;
                    377:                pcr.rule.flagset = (TH_SYN|TH_ACK);
                    378: #ifdef PFRULE_HAS_RTABLEID
                    379:                pcr.rule.rtableid = -1; /* first appeared in OpenBSD 4.0 */ 
                    380: #endif
                    381:                pcr.rule.keep_state = 1;
                    382:                strlcpy(pcr.rule.label, desc, PF_RULE_LABEL_SIZE);
                    383:                if(queue)
                    384:                        strlcpy(pcr.rule.qname, queue, PF_QNAME_SIZE);
                    385:                if(tag)
                    386:                        strlcpy(pcr.rule.tagname, tag, PF_TAG_NAME_SIZE);
                    387: 
1.1.1.2 ! misho     388:                if(rhost && rhost[0] != '\0' && rhost[0] != '*')
        !           389:                {
        !           390:                        inet_pton(AF_INET, rhost, &pcr.rule.src.addr.v.a.addr.v4.s_addr);
        !           391:                        pcr.rule.src.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
        !           392:                }
1.1       misho     393: #ifndef PF_NEWSTYLE
                    394:                pcr.rule.rpool.proxy_port[0] = eport;
                    395:                a = calloc(1, sizeof(struct pf_pooladdr));
                    396:                inet_pton(AF_INET, iaddr, &a->addr.v.a.addr.v4.s_addr);
                    397:                a->addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
                    398:                memcpy(&pp.addr, a, sizeof(struct pf_pooladdr));
                    399:                TAILQ_INIT(&pcr.rule.rpool.list);
                    400:                inet_pton(AF_INET, iaddr, &a->addr.v.a.addr.v4.s_addr);
                    401:                TAILQ_INSERT_TAIL(&pcr.rule.rpool.list, a, entries);
                    402:                
                    403:                /* we have any - any port = # keep state label */
                    404:                /* we want any - iaddr port = # keep state label */
                    405:                /* memcpy(&pcr.rule.dst, a, sizeof(struct pf_pooladdr)); */
                    406: 
                    407:                memcpy(&pp.addr, a, sizeof(struct pf_pooladdr));
                    408:                strlcpy(pcr.rule.label, desc, PF_RULE_LABEL_SIZE);
                    409:                if(ioctl(dev, DIOCADDADDR, &pp) < 0)
                    410:                {
                    411:                        syslog(LOG_ERR, "ioctl(dev, DIOCADDADDR, ...): %m");
                    412:                        r = -1;
                    413:                }
                    414:                else
                    415:                {
                    416: #else
                    417:                if(1)
                    418:                {
                    419: #endif
                    420:                        pcr.action = PF_CHANGE_GET_TICKET;
                    421:                if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
                    422:                        {
                    423:                syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
                    424:                                r = -1;
                    425:                        }
                    426:                        else
                    427:                        {
                    428:                                pcr.action = PF_CHANGE_ADD_TAIL;
                    429:                                if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
                    430:                                {
                    431:                                        syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_ADD_TAIL: %m");
                    432:                                        r = -1;
                    433:                                }
                    434:                        }
                    435:                }
                    436: #ifndef PF_NEWSTYLE
                    437:                free(a);
                    438: #endif
                    439:        }
                    440:        return r;
                    441: #endif
                    442: }
                    443: 
                    444: /* get_redirect_rule()
                    445:  * return value : 0 success (found)
                    446:  * -1 = error or rule not found */
                    447: int
                    448: get_redirect_rule(const char * ifname, unsigned short eport, int proto,
                    449:                   char * iaddr, int iaddrlen, unsigned short * iport,
                    450:                   char * desc, int desclen,
1.1.1.2 ! misho     451:                   char * rhost, int rhostlen,
        !           452:                   unsigned int * timestamp,
1.1       misho     453:                   u_int64_t * packets, u_int64_t * bytes)
                    454: {
                    455:        int i, n;
                    456:        struct pfioc_rule pr;
                    457: #ifndef PF_NEWSTYLE
                    458:        struct pfioc_pooladdr pp;
                    459: #endif
                    460:        if(dev<0) {
                    461:                syslog(LOG_ERR, "pf device is not open");
                    462:                return -1;
                    463:        }
                    464:        memset(&pr, 0, sizeof(pr));
                    465:        strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
                    466: #ifndef PF_NEWSTYLE
                    467:        pr.rule.action = PF_RDR;
                    468: #endif
                    469:        if(ioctl(dev, DIOCGETRULES, &pr) < 0)
                    470:        {
                    471:                syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
                    472:                goto error;
                    473:        }
                    474:        n = pr.nr;
                    475:        for(i=0; i<n; i++)
                    476:        {
                    477:                pr.nr = i;
                    478:                if(ioctl(dev, DIOCGETRULE, &pr) < 0)
                    479:                {
                    480:                        syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
                    481:                        goto error;
                    482:                }
                    483:                if( (eport == ntohs(pr.rule.dst.port[0]))
                    484:                  && (eport == ntohs(pr.rule.dst.port[1]))
                    485:                  && (pr.rule.proto == proto) )
                    486:                {
                    487: #ifndef PF_NEWSTYLE
                    488:                        *iport = pr.rule.rpool.proxy_port[0];
                    489: #else
                    490:                        *iport = pr.rule.rdr.proxy_port[0];
                    491: #endif
                    492:                        if(desc)
                    493:                                strlcpy(desc, pr.rule.label, desclen);
                    494: #ifdef PFRULE_INOUT_COUNTS
                    495:                        if(packets)
                    496:                                *packets = pr.rule.packets[0] + pr.rule.packets[1];
                    497:                        if(bytes)
                    498:                                *bytes = pr.rule.bytes[0] + pr.rule.bytes[1];
                    499: #else
                    500:                        if(packets)
                    501:                                *packets = pr.rule.packets;
                    502:                        if(bytes)
                    503:                                *bytes = pr.rule.bytes;
                    504: #endif
                    505: #ifndef PF_NEWSTYLE
                    506:                        memset(&pp, 0, sizeof(pp));
                    507:                        strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
                    508:                        pp.r_action = PF_RDR;
                    509:                        pp.r_num = i;
                    510:                        pp.ticket = pr.ticket;
                    511:                        if(ioctl(dev, DIOCGETADDRS, &pp) < 0)
                    512:                        {
                    513:                                syslog(LOG_ERR, "ioctl(dev, DIOCGETADDRS, ...): %m");
                    514:                                goto error;
                    515:                        }
                    516:                        if(pp.nr != 1)
                    517:                        {
                    518:                                syslog(LOG_NOTICE, "No address associated with pf rule");
                    519:                                goto error;
                    520:                        }
                    521:                        pp.nr = 0;      /* first */
                    522:                        if(ioctl(dev, DIOCGETADDR, &pp) < 0)
                    523:                        {
                    524:                                syslog(LOG_ERR, "ioctl(dev, DIOCGETADDR, ...): %m");
                    525:                                goto error;
                    526:                        }
                    527:                        inet_ntop(AF_INET, &pp.addr.addr.v.a.addr.v4.s_addr,
                    528:                                  iaddr, iaddrlen);
                    529: #else
                    530:                        inet_ntop(AF_INET, &pr.rule.rdr.addr.v.a.addr.v4.s_addr,
                    531:                                  iaddr, iaddrlen);
                    532: #endif
1.1.1.2 ! misho     533:                        if(rhost && rhostlen > 0)
        !           534:                        {
        !           535:                                if (pr.rule.src.addr.v.a.addr.v4.s_addr == 0)
        !           536:                                {
        !           537:                                        rhost[0] = '\0'; /* empty string */
        !           538:                                }
        !           539:                                else
        !           540:                                {
        !           541:                                        inet_ntop(AF_INET, &pr.rule.src.addr.v.a.addr.v4.s_addr,
        !           542:                                                  rhost, rhostlen);
        !           543:                                }
        !           544:                        }
        !           545:                        if(timestamp)
        !           546:                                *timestamp = get_timestamp(eport, proto);
1.1       misho     547:                        return 0;
                    548:                }
                    549:        }
                    550: error:
                    551:        return -1;
                    552: }
                    553: 
                    554: int
                    555: delete_redirect_rule(const char * ifname, unsigned short eport, int proto)
                    556: {
                    557:        int i, n;
                    558:        struct pfioc_rule pr;
                    559:        if(dev<0) {
                    560:                syslog(LOG_ERR, "pf device is not open");
                    561:                return -1;
                    562:        }
                    563:        memset(&pr, 0, sizeof(pr));
                    564:        strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
                    565: #ifndef PF_NEWSTYLE
                    566:        pr.rule.action = PF_RDR;
                    567: #endif
                    568:        if(ioctl(dev, DIOCGETRULES, &pr) < 0)
                    569:        {
                    570:                syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
                    571:                goto error;
                    572:        }
                    573:        n = pr.nr;
                    574:        for(i=0; i<n; i++)
                    575:        {
                    576:                pr.nr = i;
                    577:                if(ioctl(dev, DIOCGETRULE, &pr) < 0)
                    578:                {
                    579:                        syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
                    580:                        goto error;
                    581:                }
                    582:                if( (eport == ntohs(pr.rule.dst.port[0]))
                    583:                  && (eport == ntohs(pr.rule.dst.port[1]))
                    584:                  && (pr.rule.proto == proto) )
                    585:                {
                    586:                        pr.action = PF_CHANGE_GET_TICKET;
                    587:                if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
                    588:                        {
                    589:                syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
                    590:                                goto error;
                    591:                        }
                    592:                        pr.action = PF_CHANGE_REMOVE;
                    593:                        pr.nr = i;
                    594:                        if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
                    595:                        {
                    596:                                syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m");
                    597:                                goto error;
                    598:                        }
1.1.1.2 ! misho     599:                        remove_timestamp_entry(eport, proto);
1.1       misho     600:                        return 0;
                    601:                }
                    602:        }
                    603: error:
                    604:        return -1;
                    605: }
                    606: 
                    607: int
                    608: delete_filter_rule(const char * ifname, unsigned short eport, int proto)
                    609: {
                    610: #ifndef PF_ENABLE_FILTER_RULES
                    611:        return 0;
                    612: #else
                    613:        int i, n;
                    614:        struct pfioc_rule pr;
                    615:        if(dev<0) {
                    616:                syslog(LOG_ERR, "pf device is not open");
                    617:                return -1;
                    618:        }
                    619:        memset(&pr, 0, sizeof(pr));
                    620:        strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
                    621:        pr.rule.action = PF_PASS;
                    622:        if(ioctl(dev, DIOCGETRULES, &pr) < 0)
                    623:        {
                    624:                syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
                    625:                goto error;
                    626:        }
                    627:        n = pr.nr;
                    628:        for(i=0; i<n; i++)
                    629:        {
                    630:                pr.nr = i;
                    631:                if(ioctl(dev, DIOCGETRULE, &pr) < 0)
                    632:                {
                    633:                        syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
                    634:                        goto error;
                    635:                }
                    636:                if( (eport == ntohs(pr.rule.dst.port[0]))
                    637:                  && (pr.rule.proto == proto) )
                    638:                {
                    639:                        pr.action = PF_CHANGE_GET_TICKET;
                    640:                if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
                    641:                        {
                    642:                syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
                    643:                                goto error;
                    644:                        }
                    645:                        pr.action = PF_CHANGE_REMOVE;
                    646:                        pr.nr = i;
                    647:                        if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
                    648:                        {
                    649:                                syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m");
                    650:                                goto error;
                    651:                        }
                    652:                        return 0;
                    653:                }
                    654:        }
                    655: error:
                    656:        return -1;
                    657: #endif
                    658: }
                    659: 
                    660: int
                    661: get_redirect_rule_by_index(int index,
                    662:                            char * ifname, unsigned short * eport,
                    663:                            char * iaddr, int iaddrlen, unsigned short * iport,
                    664:                            int * proto, char * desc, int desclen,
1.1.1.2 ! misho     665:                            char * rhost, int rhostlen,
        !           666:                            unsigned int * timestamp,
1.1       misho     667:                            u_int64_t * packets, u_int64_t * bytes)
                    668: {
                    669:        int n;
                    670:        struct pfioc_rule pr;
                    671: #ifndef PF_NEWSTYLE
                    672:        struct pfioc_pooladdr pp;
                    673: #endif
                    674:        if(index < 0)
                    675:                return -1;
                    676:        if(dev<0) {
                    677:                syslog(LOG_ERR, "pf device is not open");
                    678:                return -1;
                    679:        }
                    680:        memset(&pr, 0, sizeof(pr));
                    681:        strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
                    682: #ifndef PF_NEWSTYLE
                    683:        pr.rule.action = PF_RDR;
                    684: #endif
                    685:        if(ioctl(dev, DIOCGETRULES, &pr) < 0)
                    686:        {
                    687:                syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
                    688:                goto error;
                    689:        }
                    690:        n = pr.nr;
                    691:        if(index >= n)
                    692:                goto error;
                    693:        pr.nr = index;
                    694:        if(ioctl(dev, DIOCGETRULE, &pr) < 0)
                    695:        {
                    696:                syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
                    697:                goto error;
                    698:        }
                    699:        *proto = pr.rule.proto;
                    700:        *eport = ntohs(pr.rule.dst.port[0]);
                    701: #ifndef PF_NEWSTYLE
                    702:        *iport = pr.rule.rpool.proxy_port[0];
                    703: #else
                    704:        *iport = pr.rule.rdr.proxy_port[0];
                    705: #endif
                    706:        if(ifname)
                    707:                strlcpy(ifname, pr.rule.ifname, IFNAMSIZ);
                    708:        if(desc)
                    709:                strlcpy(desc, pr.rule.label, desclen);
                    710: #ifdef PFRULE_INOUT_COUNTS
                    711:        if(packets)
                    712:                *packets = pr.rule.packets[0] + pr.rule.packets[1];
                    713:        if(bytes)
                    714:                *bytes = pr.rule.bytes[0] + pr.rule.bytes[1];
                    715: #else
                    716:        if(packets)
                    717:                *packets = pr.rule.packets;
                    718:        if(bytes)
                    719:                *bytes = pr.rule.bytes;
                    720: #endif
                    721: #ifndef PF_NEWSTYLE
                    722:        memset(&pp, 0, sizeof(pp));
                    723:        strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
                    724:        pp.r_action = PF_RDR;
                    725:        pp.r_num = index;
                    726:        pp.ticket = pr.ticket;
                    727:        if(ioctl(dev, DIOCGETADDRS, &pp) < 0)
                    728:        {
                    729:                syslog(LOG_ERR, "ioctl(dev, DIOCGETADDRS, ...): %m");
                    730:                goto error;
                    731:        }
                    732:        if(pp.nr != 1)
                    733:        {
                    734:                syslog(LOG_NOTICE, "No address associated with pf rule");
                    735:                goto error;
                    736:        }
                    737:        pp.nr = 0;      /* first */
                    738:        if(ioctl(dev, DIOCGETADDR, &pp) < 0)
                    739:        {
                    740:                syslog(LOG_ERR, "ioctl(dev, DIOCGETADDR, ...): %m");
                    741:                goto error;
                    742:        }
                    743:        inet_ntop(AF_INET, &pp.addr.addr.v.a.addr.v4.s_addr,
                    744:                  iaddr, iaddrlen);
                    745: #else
                    746:        inet_ntop(AF_INET, &pr.rule.rdr.addr.v.a.addr.v4.s_addr,
                    747:                  iaddr, iaddrlen);
                    748: #endif
1.1.1.2 ! misho     749:        if(rhost && rhostlen > 0)
        !           750:        {
        !           751:                if (pr.rule.src.addr.v.a.addr.v4.s_addr == 0)
        !           752:                {
        !           753:                        rhost[0] = '\0'; /* empty string */
        !           754:                }
        !           755:                else
        !           756:                {
        !           757:                        inet_ntop(AF_INET, &pr.rule.src.addr.v.a.addr.v4.s_addr,
        !           758:                                  rhost, rhostlen);
        !           759:                }
        !           760:        }
        !           761:        if(timestamp)
        !           762:                *timestamp = get_timestamp(*eport, *proto);
1.1       misho     763:        return 0;
                    764: error:
                    765:        return -1;
                    766: }
                    767: 
1.1.1.2 ! misho     768: /* return an (malloc'ed) array of "external" port for which there is
        !           769:  * a port mapping. number is the size of the array */
        !           770: unsigned short *
        !           771: get_portmappings_in_range(unsigned short startport, unsigned short endport,
        !           772:                           int proto, unsigned int * number)
        !           773: {
        !           774:        unsigned short * array;
        !           775:        unsigned int capacity;
        !           776:        int i, n;
        !           777:        unsigned short eport;
        !           778:        struct pfioc_rule pr;
        !           779: 
        !           780:        *number = 0;
        !           781:        if(dev<0) {
        !           782:                syslog(LOG_ERR, "pf device is not open");
        !           783:                return NULL;
        !           784:        }
        !           785:        capacity = 128;
        !           786:        array = calloc(capacity, sizeof(unsigned short));
        !           787:        if(!array)
        !           788:        {
        !           789:                syslog(LOG_ERR, "get_portmappings_in_range() : calloc error");
        !           790:                return NULL;
        !           791:        }
        !           792:        memset(&pr, 0, sizeof(pr));
        !           793:        strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
        !           794: #ifndef PF_NEWSTYLE
        !           795:        pr.rule.action = PF_RDR;
        !           796: #endif
        !           797:        if(ioctl(dev, DIOCGETRULES, &pr) < 0)
        !           798:        {
        !           799:                syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
        !           800:                free(array);
        !           801:                return NULL;
        !           802:        }
        !           803:        n = pr.nr;
        !           804:        for(i=0; i<n; i++)
        !           805:        {
        !           806:                pr.nr = i;
        !           807:                if(ioctl(dev, DIOCGETRULE, &pr) < 0)
        !           808:                {
        !           809:                        syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
        !           810:                        continue;
        !           811:                }
        !           812:                eport = ntohs(pr.rule.dst.port[0]);
        !           813:                if( (eport == ntohs(pr.rule.dst.port[1]))
        !           814:                  && (pr.rule.proto == proto)
        !           815:                  && (startport <= eport) && (eport <= endport) )
        !           816:                {
        !           817:                        if(*number >= capacity)
        !           818:                        {
        !           819:                                /* need to increase the capacity of the array */
        !           820:                                capacity += 128;
        !           821:                                array = realloc(array, sizeof(unsigned short)*capacity);
        !           822:                                if(!array)
        !           823:                                {
        !           824:                                        syslog(LOG_ERR, "get_portmappings_in_range() : realloc(%lu) error", sizeof(unsigned short)*capacity);
        !           825:                                        *number = 0;
        !           826:                                        return NULL;
        !           827:                                }
        !           828:                        }
        !           829:                        array[*number] = eport;
        !           830:                        (*number)++;
        !           831:                }
        !           832:        }
        !           833:        return array;
        !           834: }
        !           835: 
1.1       misho     836: /* this function is only for testing */
                    837: #if TEST
                    838: void
                    839: list_rules(void)
                    840: {
                    841:        char buf[32];
                    842:        int i, n;
                    843:        struct pfioc_rule pr;
                    844: #ifndef PF_NEWSTYLE
                    845:        struct pfioc_pooladdr pp;
                    846: #endif
                    847: 
                    848:        if(dev<0)
                    849:        {
                    850:                perror("pf dev not open");
                    851:                return ;
                    852:        }
                    853:        memset(&pr, 0, sizeof(pr));
                    854:        strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
                    855:        pr.rule.action = PF_RDR;
                    856:        if(ioctl(dev, DIOCGETRULES, &pr) < 0)
                    857:                perror("DIOCGETRULES");
                    858:        printf("ticket = %d, nr = %d\n", pr.ticket, pr.nr);
                    859:        n = pr.nr;
                    860:        for(i=0; i<n; i++)
                    861:        {
                    862:                printf("-- rule %d --\n", i);
                    863:                pr.nr = i;
                    864:                if(ioctl(dev, DIOCGETRULE, &pr) < 0)
                    865:                        perror("DIOCGETRULE");
1.1.1.2 ! misho     866:                printf(" %s %s %d:%d -> %d:%d  proto %d keep_state=%d action=%d\n",
1.1       misho     867:                        pr.rule.ifname,
1.1.1.2 ! misho     868:                        inet_ntop(AF_INET, &pr.rule.src.addr.v.a.addr.v4.s_addr, buf, 32);
1.1       misho     869:                        (int)ntohs(pr.rule.dst.port[0]),
                    870:                        (int)ntohs(pr.rule.dst.port[1]),
                    871: #ifndef PF_NEWSTYLE
                    872:                        (int)pr.rule.rpool.proxy_port[0],
                    873:                        (int)pr.rule.rpool.proxy_port[1],
                    874: #else
                    875:                        (int)pr.rule.rdr.proxy_port[0],
                    876:                        (int)pr.rule.rdr.proxy_port[1],
                    877: #endif
                    878:                        (int)pr.rule.proto,
                    879:                        (int)pr.rule.keep_state,
                    880:                        (int)pr.rule.action);
                    881:                printf("  description: \"%s\"\n", pr.rule.label);
                    882: #ifndef PF_NEWSTYLE
                    883:                memset(&pp, 0, sizeof(pp));
                    884:                strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
                    885:                pp.r_action = PF_RDR;
                    886:                pp.r_num = i;
                    887:                pp.ticket = pr.ticket;
                    888:                if(ioctl(dev, DIOCGETADDRS, &pp) < 0)
                    889:                        perror("DIOCGETADDRS");
                    890:                printf("  nb pool addr = %d ticket=%d\n", pp.nr, pp.ticket);
                    891:                /*if(ioctl(dev, DIOCGETRULE, &pr) < 0)
                    892:                        perror("DIOCGETRULE"); */
                    893:                pp.nr = 0;      /* first */
                    894:                if(ioctl(dev, DIOCGETADDR, &pp) < 0)
                    895:                        perror("DIOCGETADDR");
                    896:                /* addr.v.a.addr.v4.s_addr */
                    897:                printf("  %s\n", inet_ntop(AF_INET, &pp.addr.addr.v.a.addr.v4.s_addr, buf, 32));
                    898: #else
                    899:                printf("  rule_flag=%08x action=%d direction=%d log=%d logif=%d "
                    900:                       "quick=%d ifnot=%d af=%d type=%d code=%d rdr.port_op=%d rdr.opts=%d\n",
                    901:                       pr.rule.rule_flag, pr.rule.action, pr.rule.direction,
                    902:                       pr.rule.log, pr.rule.logif, pr.rule.quick, pr.rule.ifnot,
                    903:                       pr.rule.af, pr.rule.type, pr.rule.code,
                    904:                       pr.rule.rdr.port_op, pr.rule.rdr.opts);
                    905:                printf("  %s\n", inet_ntop(AF_INET, &pr.rule.rdr.addr.v.a.addr.v4.s_addr, buf, 32));
                    906: #endif
                    907:        }
                    908: }
                    909: #endif
                    910: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>