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

1.1       misho       1: /* $Id: obsdrdr.c,v 1.59 2010/05/11 16:19:26 nanard Exp $ */
                      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: 
                     62: /* anchor name */
                     63: static const char anchor_name[] = "miniupnpd";
                     64: 
                     65: /* /dev/pf when opened */
                     66: static int dev = -1;
                     67: 
                     68: /* shutdown_redirect() :
                     69:  * close the /dev/pf device */
                     70: void
                     71: shutdown_redirect(void)
                     72: {
                     73:        if(close(dev)<0)
                     74:                syslog(LOG_ERR, "close(\"/dev/pf\"): %m");
                     75:        dev = -1;
                     76: }
                     77: 
                     78: /* open the device */
                     79: int
                     80: init_redirect(void)
                     81: {
                     82:        struct pf_status status;
                     83:        if(dev>=0)
                     84:                shutdown_redirect();
                     85:        dev = open("/dev/pf", O_RDWR);
                     86:        if(dev<0) {
                     87:                syslog(LOG_ERR, "open(\"/dev/pf\"): %m");
                     88:                return -1;
                     89:        }
                     90:        if(ioctl(dev, DIOCGETSTATUS, &status)<0) {
                     91:                syslog(LOG_ERR, "DIOCGETSTATUS: %m");
                     92:                return -1;
                     93:        }
                     94:        if(!status.running) {
                     95:                syslog(LOG_ERR, "pf is disabled");
                     96:                return -1;
                     97:        }
                     98:        return 0;
                     99: }
                    100: 
                    101: #if TEST
                    102: /* for debug */
                    103: int
                    104: clear_redirect_rules(void)
                    105: {
                    106:        struct pfioc_trans io;
                    107:        struct pfioc_trans_e ioe;
                    108:        if(dev<0) {
                    109:                syslog(LOG_ERR, "pf device is not open");
                    110:                return -1;
                    111:        }
                    112:        memset(&ioe, 0, sizeof(ioe));
                    113:        io.size = 1;
                    114:        io.esize = sizeof(ioe);
                    115:        io.array = &ioe;
                    116: #ifndef PF_NEWSTYLE
                    117:        ioe.rs_num = PF_RULESET_RDR;
                    118: #else
                    119:        ioe.type = PF_TRANS_RULESET;
                    120: #endif
                    121:        strlcpy(ioe.anchor, anchor_name, MAXPATHLEN);
                    122:        if(ioctl(dev, DIOCXBEGIN, &io) < 0)
                    123:        {
                    124:                syslog(LOG_ERR, "ioctl(dev, DIOCXBEGIN, ...): %m");
                    125:                goto error;
                    126:        }
                    127:        if(ioctl(dev, DIOCXCOMMIT, &io) < 0)
                    128:        {
                    129:                syslog(LOG_ERR, "ioctl(dev, DIOCXCOMMIT, ...): %m");
                    130:                goto error;
                    131:        }
                    132:        return 0;
                    133: error:
                    134:        return -1;
                    135: }
                    136: #endif
                    137: 
                    138: /* add_redirect_rule2() :
                    139:  * create a rdr rule */
                    140: int
                    141: add_redirect_rule2(const char * ifname, unsigned short eport,
                    142:                    const char * iaddr, unsigned short iport, int proto,
                    143:                                   const char * desc)
                    144: {
                    145:        int r;
                    146:        struct pfioc_rule pcr;
                    147: #ifndef PF_NEWSTYLE
                    148:        struct pfioc_pooladdr pp;
                    149:        struct pf_pooladdr *a;
                    150: #endif
                    151:        if(dev<0) {
                    152:                syslog(LOG_ERR, "pf device is not open");
                    153:                return -1;
                    154:        }
                    155:        r = 0;
                    156:        memset(&pcr, 0, sizeof(pcr));
                    157:        strlcpy(pcr.anchor, anchor_name, MAXPATHLEN);
                    158: 
                    159: #ifndef PF_NEWSTYLE
                    160:        memset(&pp, 0, sizeof(pp));
                    161:        strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
                    162:        if(ioctl(dev, DIOCBEGINADDRS, &pp) < 0)
                    163:        {
                    164:                syslog(LOG_ERR, "ioctl(dev, DIOCBEGINADDRS, ...): %m");
                    165:                r = -1;
                    166:        }
                    167:        else
                    168:        {
                    169:                pcr.pool_ticket = pp.ticket;
                    170: #else
                    171:        if(1)
                    172:        {
                    173:                pcr.rule.direction = PF_IN;
                    174:                //pcr.rule.src.addr.type = PF_ADDR_NONE;
                    175:                pcr.rule.src.addr.type = PF_ADDR_ADDRMASK;
                    176:                pcr.rule.dst.addr.type = PF_ADDR_ADDRMASK;
                    177:                pcr.rule.nat.addr.type = PF_ADDR_NONE;
                    178:                pcr.rule.rdr.addr.type = PF_ADDR_ADDRMASK;
                    179: #endif
                    180:                
                    181:                pcr.rule.dst.port_op = PF_OP_EQ;
                    182:                pcr.rule.dst.port[0] = htons(eport);
                    183:                pcr.rule.dst.port[1] = htons(eport);
                    184: #ifndef PF_NEWSTYLE
                    185:                pcr.rule.action = PF_RDR;
                    186: #ifndef PF_ENABLE_FILTER_RULES
                    187:                pcr.rule.natpass = 1;
                    188: #else
                    189:                pcr.rule.natpass = 0;
                    190: #endif
                    191: #else
                    192: #ifndef PF_ENABLE_FILTER_RULES
                    193:                pcr.rule.action = PF_PASS;
                    194: #else
                    195:                pcr.rule.action = PF_MATCH;
                    196: #endif
                    197: #endif
                    198:                pcr.rule.af = AF_INET;
                    199: #ifdef USE_IFNAME_IN_RULES
                    200:                if(ifname)
                    201:                        strlcpy(pcr.rule.ifname, ifname, IFNAMSIZ);
                    202: #endif
                    203:                pcr.rule.proto = proto;
                    204:                pcr.rule.log = (GETFLAG(LOGPACKETSMASK))?1:0;   /*logpackets;*/
                    205: #ifdef PFRULE_HAS_RTABLEID
                    206:                pcr.rule.rtableid = -1; /* first appeared in OpenBSD 4.0 */
                    207: #endif
                    208:                pcr.rule.quick = 1;
                    209:                pcr.rule.keep_state = PF_STATE_NORMAL;
                    210:                if(tag)
                    211:                        strlcpy(pcr.rule.tagname, tag, PF_TAG_NAME_SIZE);
                    212:                strlcpy(pcr.rule.label, desc, PF_RULE_LABEL_SIZE);
                    213: #ifndef PF_NEWSTYLE
                    214:                pcr.rule.rpool.proxy_port[0] = iport;
                    215:                pcr.rule.rpool.proxy_port[1] = iport;
                    216:                TAILQ_INIT(&pcr.rule.rpool.list);
                    217:                a = calloc(1, sizeof(struct pf_pooladdr));
                    218:                inet_pton(AF_INET, iaddr, &a->addr.v.a.addr.v4.s_addr);
                    219:                a->addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
                    220:                TAILQ_INSERT_TAIL(&pcr.rule.rpool.list, a, entries);
                    221: 
                    222:                memcpy(&pp.addr, a, sizeof(struct pf_pooladdr));
                    223:                if(ioctl(dev, DIOCADDADDR, &pp) < 0)
                    224:                {
                    225:                        syslog(LOG_ERR, "ioctl(dev, DIOCADDADDR, ...): %m");
                    226:                        r = -1;
                    227:                }
                    228:                else
                    229:                {
                    230: #else
                    231:                pcr.rule.rdr.proxy_port[0] = iport;
                    232:                pcr.rule.rdr.proxy_port[1] = iport;
                    233:                inet_pton(AF_INET, iaddr, &pcr.rule.rdr.addr.v.a.addr.v4.s_addr);
                    234:                pcr.rule.rdr.addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
                    235:                if(1)
                    236:                {
                    237: #endif
                    238:                        pcr.action = PF_CHANGE_GET_TICKET;
                    239:                if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
                    240:                        {
                    241:                syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
                    242:                                r = -1;
                    243:                        }
                    244:                        else
                    245:                        {
                    246:                                pcr.action = PF_CHANGE_ADD_TAIL;
                    247:                                if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
                    248:                                {
                    249:                                        syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_ADD_TAIL: %m");
                    250:                                        r = -1;
                    251:                                }
                    252:                        }
                    253:                }
                    254: #ifndef PF_NEWSTYLE
                    255:                free(a);
                    256: #endif
                    257:        }
                    258:        return r;
                    259: }
                    260: 
                    261: /* thanks to Seth Mos for this function */
                    262: int
                    263: add_filter_rule2(const char * ifname, const char * iaddr,
                    264:                  unsigned short eport, unsigned short iport,
                    265:                                 int proto, const char * desc)
                    266: {
                    267: #ifndef PF_ENABLE_FILTER_RULES
                    268:        return 0;
                    269: #else
                    270:        int r;
                    271:        struct pfioc_rule pcr;
                    272: #ifndef PF_NEWSTYLE
                    273:        struct pfioc_pooladdr pp;
                    274:        struct pf_pooladdr *a;
                    275: #endif
                    276:        if(dev<0) {
                    277:                syslog(LOG_ERR, "pf device is not open");
                    278:                return -1;
                    279:        }
                    280:        r = 0;
                    281:        memset(&pcr, 0, sizeof(pcr));
                    282:        strlcpy(pcr.anchor, anchor_name, MAXPATHLEN);
                    283: 
                    284: #ifndef PF_NEWSTYLE
                    285:        memset(&pp, 0, sizeof(pp));
                    286:        strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
                    287:        if(ioctl(dev, DIOCBEGINADDRS, &pp) < 0)
                    288:        {
                    289:                syslog(LOG_ERR, "ioctl(dev, DIOCBEGINADDRS, ...): %m");
                    290:                r = -1;
                    291:        }
                    292:        else
                    293:        {
                    294:                pcr.pool_ticket = pp.ticket;
                    295: #else
                    296:        if(1)
                    297:        {
                    298: #endif
                    299:                
                    300:                pcr.rule.dst.port_op = PF_OP_EQ;
                    301:                pcr.rule.dst.port[0] = htons(eport);
                    302:                pcr.rule.direction = PF_IN;
                    303:                pcr.rule.action = PF_PASS;
                    304:                pcr.rule.af = AF_INET;
                    305: #ifdef USE_IFNAME_IN_RULES
                    306:                if(ifname)
                    307:                        strlcpy(pcr.rule.ifname, ifname, IFNAMSIZ);
                    308: #endif
                    309:                pcr.rule.proto = proto;
                    310:                pcr.rule.quick = (GETFLAG(PFNOQUICKRULESMASK))?0:1;
                    311:                pcr.rule.log = (GETFLAG(LOGPACKETSMASK))?1:0;   /*logpackets;*/
                    312: /* see the discussion on the forum :
                    313:  * http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=638 */
                    314:                pcr.rule.flags = TH_SYN;
                    315:                pcr.rule.flagset = (TH_SYN|TH_ACK);
                    316: #ifdef PFRULE_HAS_RTABLEID
                    317:                pcr.rule.rtableid = -1; /* first appeared in OpenBSD 4.0 */ 
                    318: #endif
                    319:                pcr.rule.keep_state = 1;
                    320:                strlcpy(pcr.rule.label, desc, PF_RULE_LABEL_SIZE);
                    321:                if(queue)
                    322:                        strlcpy(pcr.rule.qname, queue, PF_QNAME_SIZE);
                    323:                if(tag)
                    324:                        strlcpy(pcr.rule.tagname, tag, PF_TAG_NAME_SIZE);
                    325: 
                    326: #ifndef PF_NEWSTYLE
                    327:                pcr.rule.rpool.proxy_port[0] = eport;
                    328:                a = calloc(1, sizeof(struct pf_pooladdr));
                    329:                inet_pton(AF_INET, iaddr, &a->addr.v.a.addr.v4.s_addr);
                    330:                a->addr.v.a.mask.v4.s_addr = htonl(INADDR_NONE);
                    331:                memcpy(&pp.addr, a, sizeof(struct pf_pooladdr));
                    332:                TAILQ_INIT(&pcr.rule.rpool.list);
                    333:                inet_pton(AF_INET, iaddr, &a->addr.v.a.addr.v4.s_addr);
                    334:                TAILQ_INSERT_TAIL(&pcr.rule.rpool.list, a, entries);
                    335:                
                    336:                /* we have any - any port = # keep state label */
                    337:                /* we want any - iaddr port = # keep state label */
                    338:                /* memcpy(&pcr.rule.dst, a, sizeof(struct pf_pooladdr)); */
                    339: 
                    340:                memcpy(&pp.addr, a, sizeof(struct pf_pooladdr));
                    341:                strlcpy(pcr.rule.label, desc, PF_RULE_LABEL_SIZE);
                    342:                if(ioctl(dev, DIOCADDADDR, &pp) < 0)
                    343:                {
                    344:                        syslog(LOG_ERR, "ioctl(dev, DIOCADDADDR, ...): %m");
                    345:                        r = -1;
                    346:                }
                    347:                else
                    348:                {
                    349: #else
                    350:                if(1)
                    351:                {
                    352: #endif
                    353:                        pcr.action = PF_CHANGE_GET_TICKET;
                    354:                if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
                    355:                        {
                    356:                syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
                    357:                                r = -1;
                    358:                        }
                    359:                        else
                    360:                        {
                    361:                                pcr.action = PF_CHANGE_ADD_TAIL;
                    362:                                if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0)
                    363:                                {
                    364:                                        syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_ADD_TAIL: %m");
                    365:                                        r = -1;
                    366:                                }
                    367:                        }
                    368:                }
                    369: #ifndef PF_NEWSTYLE
                    370:                free(a);
                    371: #endif
                    372:        }
                    373:        return r;
                    374: #endif
                    375: }
                    376: 
                    377: /* get_redirect_rule()
                    378:  * return value : 0 success (found)
                    379:  * -1 = error or rule not found */
                    380: int
                    381: get_redirect_rule(const char * ifname, unsigned short eport, int proto,
                    382:                   char * iaddr, int iaddrlen, unsigned short * iport,
                    383:                   char * desc, int desclen,
                    384:                   u_int64_t * packets, u_int64_t * bytes)
                    385: {
                    386:        int i, n;
                    387:        struct pfioc_rule pr;
                    388: #ifndef PF_NEWSTYLE
                    389:        struct pfioc_pooladdr pp;
                    390: #endif
                    391:        if(dev<0) {
                    392:                syslog(LOG_ERR, "pf device is not open");
                    393:                return -1;
                    394:        }
                    395:        memset(&pr, 0, sizeof(pr));
                    396:        strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
                    397: #ifndef PF_NEWSTYLE
                    398:        pr.rule.action = PF_RDR;
                    399: #endif
                    400:        if(ioctl(dev, DIOCGETRULES, &pr) < 0)
                    401:        {
                    402:                syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
                    403:                goto error;
                    404:        }
                    405:        n = pr.nr;
                    406:        for(i=0; i<n; i++)
                    407:        {
                    408:                pr.nr = i;
                    409:                if(ioctl(dev, DIOCGETRULE, &pr) < 0)
                    410:                {
                    411:                        syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
                    412:                        goto error;
                    413:                }
                    414:                if( (eport == ntohs(pr.rule.dst.port[0]))
                    415:                  && (eport == ntohs(pr.rule.dst.port[1]))
                    416:                  && (pr.rule.proto == proto) )
                    417:                {
                    418: #ifndef PF_NEWSTYLE
                    419:                        *iport = pr.rule.rpool.proxy_port[0];
                    420: #else
                    421:                        *iport = pr.rule.rdr.proxy_port[0];
                    422: #endif
                    423:                        if(desc)
                    424:                                strlcpy(desc, pr.rule.label, desclen);
                    425: #ifdef PFRULE_INOUT_COUNTS
                    426:                        if(packets)
                    427:                                *packets = pr.rule.packets[0] + pr.rule.packets[1];
                    428:                        if(bytes)
                    429:                                *bytes = pr.rule.bytes[0] + pr.rule.bytes[1];
                    430: #else
                    431:                        if(packets)
                    432:                                *packets = pr.rule.packets;
                    433:                        if(bytes)
                    434:                                *bytes = pr.rule.bytes;
                    435: #endif
                    436: #ifndef PF_NEWSTYLE
                    437:                        memset(&pp, 0, sizeof(pp));
                    438:                        strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
                    439:                        pp.r_action = PF_RDR;
                    440:                        pp.r_num = i;
                    441:                        pp.ticket = pr.ticket;
                    442:                        if(ioctl(dev, DIOCGETADDRS, &pp) < 0)
                    443:                        {
                    444:                                syslog(LOG_ERR, "ioctl(dev, DIOCGETADDRS, ...): %m");
                    445:                                goto error;
                    446:                        }
                    447:                        if(pp.nr != 1)
                    448:                        {
                    449:                                syslog(LOG_NOTICE, "No address associated with pf rule");
                    450:                                goto error;
                    451:                        }
                    452:                        pp.nr = 0;      /* first */
                    453:                        if(ioctl(dev, DIOCGETADDR, &pp) < 0)
                    454:                        {
                    455:                                syslog(LOG_ERR, "ioctl(dev, DIOCGETADDR, ...): %m");
                    456:                                goto error;
                    457:                        }
                    458:                        inet_ntop(AF_INET, &pp.addr.addr.v.a.addr.v4.s_addr,
                    459:                                  iaddr, iaddrlen);
                    460: #else
                    461:                        inet_ntop(AF_INET, &pr.rule.rdr.addr.v.a.addr.v4.s_addr,
                    462:                                  iaddr, iaddrlen);
                    463: #endif
                    464:                        return 0;
                    465:                }
                    466:        }
                    467: error:
                    468:        return -1;
                    469: }
                    470: 
                    471: int
                    472: delete_redirect_rule(const char * ifname, unsigned short eport, int proto)
                    473: {
                    474:        int i, n;
                    475:        struct pfioc_rule pr;
                    476:        if(dev<0) {
                    477:                syslog(LOG_ERR, "pf device is not open");
                    478:                return -1;
                    479:        }
                    480:        memset(&pr, 0, sizeof(pr));
                    481:        strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
                    482: #ifndef PF_NEWSTYLE
                    483:        pr.rule.action = PF_RDR;
                    484: #endif
                    485:        if(ioctl(dev, DIOCGETRULES, &pr) < 0)
                    486:        {
                    487:                syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
                    488:                goto error;
                    489:        }
                    490:        n = pr.nr;
                    491:        for(i=0; i<n; i++)
                    492:        {
                    493:                pr.nr = i;
                    494:                if(ioctl(dev, DIOCGETRULE, &pr) < 0)
                    495:                {
                    496:                        syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
                    497:                        goto error;
                    498:                }
                    499:                if( (eport == ntohs(pr.rule.dst.port[0]))
                    500:                  && (eport == ntohs(pr.rule.dst.port[1]))
                    501:                  && (pr.rule.proto == proto) )
                    502:                {
                    503:                        pr.action = PF_CHANGE_GET_TICKET;
                    504:                if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
                    505:                        {
                    506:                syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
                    507:                                goto error;
                    508:                        }
                    509:                        pr.action = PF_CHANGE_REMOVE;
                    510:                        pr.nr = i;
                    511:                        if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
                    512:                        {
                    513:                                syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m");
                    514:                                goto error;
                    515:                        }
                    516:                        return 0;
                    517:                }
                    518:        }
                    519: error:
                    520:        return -1;
                    521: }
                    522: 
                    523: int
                    524: delete_filter_rule(const char * ifname, unsigned short eport, int proto)
                    525: {
                    526: #ifndef PF_ENABLE_FILTER_RULES
                    527:        return 0;
                    528: #else
                    529:        int i, n;
                    530:        struct pfioc_rule pr;
                    531:        if(dev<0) {
                    532:                syslog(LOG_ERR, "pf device is not open");
                    533:                return -1;
                    534:        }
                    535:        memset(&pr, 0, sizeof(pr));
                    536:        strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
                    537:        pr.rule.action = PF_PASS;
                    538:        if(ioctl(dev, DIOCGETRULES, &pr) < 0)
                    539:        {
                    540:                syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
                    541:                goto error;
                    542:        }
                    543:        n = pr.nr;
                    544:        for(i=0; i<n; i++)
                    545:        {
                    546:                pr.nr = i;
                    547:                if(ioctl(dev, DIOCGETRULE, &pr) < 0)
                    548:                {
                    549:                        syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
                    550:                        goto error;
                    551:                }
                    552:                if( (eport == ntohs(pr.rule.dst.port[0]))
                    553:                  && (pr.rule.proto == proto) )
                    554:                {
                    555:                        pr.action = PF_CHANGE_GET_TICKET;
                    556:                if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
                    557:                        {
                    558:                syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
                    559:                                goto error;
                    560:                        }
                    561:                        pr.action = PF_CHANGE_REMOVE;
                    562:                        pr.nr = i;
                    563:                        if(ioctl(dev, DIOCCHANGERULE, &pr) < 0)
                    564:                        {
                    565:                                syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m");
                    566:                                goto error;
                    567:                        }
                    568:                        return 0;
                    569:                }
                    570:        }
                    571: error:
                    572:        return -1;
                    573: #endif
                    574: }
                    575: 
                    576: int
                    577: get_redirect_rule_by_index(int index,
                    578:                            char * ifname, unsigned short * eport,
                    579:                            char * iaddr, int iaddrlen, unsigned short * iport,
                    580:                            int * proto, char * desc, int desclen,
                    581:                            u_int64_t * packets, u_int64_t * bytes)
                    582: {
                    583:        int n;
                    584:        struct pfioc_rule pr;
                    585: #ifndef PF_NEWSTYLE
                    586:        struct pfioc_pooladdr pp;
                    587: #endif
                    588:        if(index < 0)
                    589:                return -1;
                    590:        if(dev<0) {
                    591:                syslog(LOG_ERR, "pf device is not open");
                    592:                return -1;
                    593:        }
                    594:        memset(&pr, 0, sizeof(pr));
                    595:        strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
                    596: #ifndef PF_NEWSTYLE
                    597:        pr.rule.action = PF_RDR;
                    598: #endif
                    599:        if(ioctl(dev, DIOCGETRULES, &pr) < 0)
                    600:        {
                    601:                syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
                    602:                goto error;
                    603:        }
                    604:        n = pr.nr;
                    605:        if(index >= n)
                    606:                goto error;
                    607:        pr.nr = index;
                    608:        if(ioctl(dev, DIOCGETRULE, &pr) < 0)
                    609:        {
                    610:                syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
                    611:                goto error;
                    612:        }
                    613:        *proto = pr.rule.proto;
                    614:        *eport = ntohs(pr.rule.dst.port[0]);
                    615: #ifndef PF_NEWSTYLE
                    616:        *iport = pr.rule.rpool.proxy_port[0];
                    617: #else
                    618:        *iport = pr.rule.rdr.proxy_port[0];
                    619: #endif
                    620:        if(ifname)
                    621:                strlcpy(ifname, pr.rule.ifname, IFNAMSIZ);
                    622:        if(desc)
                    623:                strlcpy(desc, pr.rule.label, desclen);
                    624: #ifdef PFRULE_INOUT_COUNTS
                    625:        if(packets)
                    626:                *packets = pr.rule.packets[0] + pr.rule.packets[1];
                    627:        if(bytes)
                    628:                *bytes = pr.rule.bytes[0] + pr.rule.bytes[1];
                    629: #else
                    630:        if(packets)
                    631:                *packets = pr.rule.packets;
                    632:        if(bytes)
                    633:                *bytes = pr.rule.bytes;
                    634: #endif
                    635: #ifndef PF_NEWSTYLE
                    636:        memset(&pp, 0, sizeof(pp));
                    637:        strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
                    638:        pp.r_action = PF_RDR;
                    639:        pp.r_num = index;
                    640:        pp.ticket = pr.ticket;
                    641:        if(ioctl(dev, DIOCGETADDRS, &pp) < 0)
                    642:        {
                    643:                syslog(LOG_ERR, "ioctl(dev, DIOCGETADDRS, ...): %m");
                    644:                goto error;
                    645:        }
                    646:        if(pp.nr != 1)
                    647:        {
                    648:                syslog(LOG_NOTICE, "No address associated with pf rule");
                    649:                goto error;
                    650:        }
                    651:        pp.nr = 0;      /* first */
                    652:        if(ioctl(dev, DIOCGETADDR, &pp) < 0)
                    653:        {
                    654:                syslog(LOG_ERR, "ioctl(dev, DIOCGETADDR, ...): %m");
                    655:                goto error;
                    656:        }
                    657:        inet_ntop(AF_INET, &pp.addr.addr.v.a.addr.v4.s_addr,
                    658:                  iaddr, iaddrlen);
                    659: #else
                    660:        inet_ntop(AF_INET, &pr.rule.rdr.addr.v.a.addr.v4.s_addr,
                    661:                  iaddr, iaddrlen);
                    662: #endif
                    663:        return 0;
                    664: error:
                    665:        return -1;
                    666: }
                    667: 
                    668: /* this function is only for testing */
                    669: #if TEST
                    670: void
                    671: list_rules(void)
                    672: {
                    673:        char buf[32];
                    674:        int i, n;
                    675:        struct pfioc_rule pr;
                    676: #ifndef PF_NEWSTYLE
                    677:        struct pfioc_pooladdr pp;
                    678: #endif
                    679: 
                    680:        if(dev<0)
                    681:        {
                    682:                perror("pf dev not open");
                    683:                return ;
                    684:        }
                    685:        memset(&pr, 0, sizeof(pr));
                    686:        strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
                    687:        pr.rule.action = PF_RDR;
                    688:        if(ioctl(dev, DIOCGETRULES, &pr) < 0)
                    689:                perror("DIOCGETRULES");
                    690:        printf("ticket = %d, nr = %d\n", pr.ticket, pr.nr);
                    691:        n = pr.nr;
                    692:        for(i=0; i<n; i++)
                    693:        {
                    694:                printf("-- rule %d --\n", i);
                    695:                pr.nr = i;
                    696:                if(ioctl(dev, DIOCGETRULE, &pr) < 0)
                    697:                        perror("DIOCGETRULE");
                    698:                printf(" %s %d:%d -> %d:%d  proto %d keep_state=%d action=%d\n",
                    699:                        pr.rule.ifname,
                    700:                        (int)ntohs(pr.rule.dst.port[0]),
                    701:                        (int)ntohs(pr.rule.dst.port[1]),
                    702: #ifndef PF_NEWSTYLE
                    703:                        (int)pr.rule.rpool.proxy_port[0],
                    704:                        (int)pr.rule.rpool.proxy_port[1],
                    705: #else
                    706:                        (int)pr.rule.rdr.proxy_port[0],
                    707:                        (int)pr.rule.rdr.proxy_port[1],
                    708: #endif
                    709:                        (int)pr.rule.proto,
                    710:                        (int)pr.rule.keep_state,
                    711:                        (int)pr.rule.action);
                    712:                printf("  description: \"%s\"\n", pr.rule.label);
                    713: #ifndef PF_NEWSTYLE
                    714:                memset(&pp, 0, sizeof(pp));
                    715:                strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
                    716:                pp.r_action = PF_RDR;
                    717:                pp.r_num = i;
                    718:                pp.ticket = pr.ticket;
                    719:                if(ioctl(dev, DIOCGETADDRS, &pp) < 0)
                    720:                        perror("DIOCGETADDRS");
                    721:                printf("  nb pool addr = %d ticket=%d\n", pp.nr, pp.ticket);
                    722:                /*if(ioctl(dev, DIOCGETRULE, &pr) < 0)
                    723:                        perror("DIOCGETRULE"); */
                    724:                pp.nr = 0;      /* first */
                    725:                if(ioctl(dev, DIOCGETADDR, &pp) < 0)
                    726:                        perror("DIOCGETADDR");
                    727:                /* addr.v.a.addr.v4.s_addr */
                    728:                printf("  %s\n", inet_ntop(AF_INET, &pp.addr.addr.v.a.addr.v4.s_addr, buf, 32));
                    729: #else
                    730:                printf("  rule_flag=%08x action=%d direction=%d log=%d logif=%d "
                    731:                       "quick=%d ifnot=%d af=%d type=%d code=%d rdr.port_op=%d rdr.opts=%d\n",
                    732:                       pr.rule.rule_flag, pr.rule.action, pr.rule.direction,
                    733:                       pr.rule.log, pr.rule.logif, pr.rule.quick, pr.rule.ifnot,
                    734:                       pr.rule.af, pr.rule.type, pr.rule.code,
                    735:                       pr.rule.rdr.port_op, pr.rule.rdr.opts);
                    736:                printf("  %s\n", inet_ntop(AF_INET, &pr.rule.rdr.addr.v.a.addr.v4.s_addr, buf, 32));
                    737: #endif
                    738:        }
                    739: }
                    740: #endif
                    741: 

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