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

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

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