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

1.1       misho       1: /* $Id: pfpinhole.c,v 1.19 2012/05/21 15:47:57 nanard Exp $ */
                      2: /* MiniUPnP project
                      3:  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
                      4:  * (c) 2012 Thomas Bernard
                      5:  * This software is subject to the conditions detailed
                      6:  * in the LICENCE file provided within the distribution */
                      7: 
                      8: #include <sys/types.h>
                      9: #include <sys/socket.h>
                     10: #include <sys/param.h>
                     11: #include <net/if.h>
                     12: #include <netinet/in.h>
                     13: #include <netinet/tcp.h>
                     14: #include <arpa/inet.h>
                     15: #ifdef __DragonFly__
                     16: #include <net/pf/pfvar.h>
                     17: #else
                     18: #include <net/pfvar.h>
                     19: #endif
                     20: #include <fcntl.h>
                     21: #include <sys/ioctl.h>
                     22: #include <unistd.h>
                     23: #include <string.h>
                     24: #include <syslog.h>
                     25: #include <stdio.h>
                     26: #include <stdlib.h>
                     27: 
                     28: #include "../config.h"
                     29: #include "pfpinhole.h"
                     30: #include "../upnpglobalvars.h"
                     31: 
                     32: /* the pass rules created by add_pinhole() are as follow :
                     33:  *
                     34:  * pass in quick on ep0 inet6 proto udp
                     35:  *   from any to dead:beef::42:42 port = 8080
                     36:  *   flags S/SA keep state
                     37:  *   label "pinhole-2 ts-4321000"
                     38:  *
                     39:  * with the label "pinhole-$uid ts-$timestamp"
                     40:  */
                     41: 
                     42: #ifdef ENABLE_6FC_SERVICE
                     43: /* /dev/pf when opened */
                     44: extern int dev;
                     45: 
                     46: static int next_uid = 1;
                     47: 
                     48: #define PINEHOLE_LABEL_FORMAT "pinhole-%d ts-%u"
                     49: 
                     50: int add_pinhole(const char * ifname,
                     51:                 const char * rem_host, unsigned short rem_port,
                     52:                 const char * int_client, unsigned short int_port,
                     53:                 int proto, unsigned int timestamp)
                     54: {
                     55:        int uid;
                     56:        struct pfioc_rule pcr;
                     57: #ifndef PF_NEWSTYLE
                     58:        struct pfioc_pooladdr pp;
                     59: #endif
                     60: 
                     61:        if(dev<0) {
                     62:                syslog(LOG_ERR, "pf device is not open");
                     63:                return -1;
                     64:        }
                     65:        memset(&pcr, 0, sizeof(pcr));
                     66:        strlcpy(pcr.anchor, anchor_name, MAXPATHLEN);
                     67: 
                     68: #ifndef PF_NEWSTYLE
                     69:        memset(&pp, 0, sizeof(pp));
                     70:        strlcpy(pp.anchor, anchor_name, MAXPATHLEN);
                     71:        if(ioctl(dev, DIOCBEGINADDRS, &pp) < 0) {
                     72:                syslog(LOG_ERR, "ioctl(dev, DIOCBEGINADDRS, ...): %m");
                     73:                return -1;
                     74:        } else {
                     75:                pcr.pool_ticket = pp.ticket;
                     76: #else
                     77:        {
                     78: #endif
                     79:                pcr.rule.direction = PF_IN;
                     80:                pcr.rule.action = PF_PASS;
                     81:                pcr.rule.af = AF_INET6;
                     82: #ifdef PF_NEWSTYLE
                     83:                pcr.rule.nat.addr.type = PF_ADDR_NONE;
                     84:                pcr.rule.rdr.addr.type = PF_ADDR_NONE;
                     85: #endif
                     86: #ifdef USE_IFNAME_IN_RULES
                     87:                if(ifname)
                     88:                        strlcpy(pcr.rule.ifname, ifname, IFNAMSIZ);
                     89: #endif
                     90:                pcr.rule.proto = proto;
                     91: 
                     92:                pcr.rule.quick = 1;/*(GETFLAG(PFNOQUICKRULESMASK))?0:1;*/
                     93:                pcr.rule.log = (GETFLAG(LOGPACKETSMASK))?1:0;   /*logpackets;*/
                     94: /* see the discussion on the forum :
                     95:  * http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=638 */
                     96:                pcr.rule.flags = TH_SYN;
                     97:                pcr.rule.flagset = (TH_SYN|TH_ACK);
                     98: #ifdef PFRULE_HAS_RTABLEID
                     99:                pcr.rule.rtableid = -1; /* first appeared in OpenBSD 4.0 */
                    100: #endif
                    101: #ifdef PFRULE_HAS_ONRDOMAIN
                    102:                pcr.rule.onrdomain = -1;        /* first appeared in OpenBSD 5.0 */
                    103: #endif
                    104:                pcr.rule.keep_state = 1;
                    105:                uid = next_uid;
                    106:                snprintf(pcr.rule.label, PF_RULE_LABEL_SIZE,
                    107:                         PINEHOLE_LABEL_FORMAT, uid, timestamp);
                    108:                if(queue)
                    109:                        strlcpy(pcr.rule.qname, queue, PF_QNAME_SIZE);
                    110:                if(tag)
                    111:                        strlcpy(pcr.rule.tagname, tag, PF_TAG_NAME_SIZE);
                    112: 
                    113:                if(rem_port) {
                    114:                        pcr.rule.src.port_op = PF_OP_EQ;
                    115:                        pcr.rule.src.port[0] = htons(rem_port);
                    116:                }
                    117:                if(rem_host && rem_host[0] != '\0' && rem_host[0] != '*') {
                    118:                        pcr.rule.src.addr.type = PF_ADDR_ADDRMASK;
                    119:                        if(inet_pton(AF_INET6, rem_host, &pcr.rule.src.addr.v.a.addr.v6) != 1) {
                    120:                                syslog(LOG_ERR, "inet_pton(%s) failed", rem_host);
                    121:                        }
                    122:                        memset(&pcr.rule.src.addr.v.a.mask.addr8, 255, 16);
                    123:                }
                    124: 
                    125:                pcr.rule.dst.port_op = PF_OP_EQ;
                    126:                pcr.rule.dst.port[0] = htons(int_port);
                    127:                pcr.rule.dst.addr.type = PF_ADDR_ADDRMASK;
                    128:                if(inet_pton(AF_INET6, int_client, &pcr.rule.dst.addr.v.a.addr.v6) != 1) {
                    129:                        syslog(LOG_ERR, "inet_pton(%s) failed", int_client);
                    130:                }
                    131:                memset(&pcr.rule.dst.addr.v.a.mask.addr8, 255, 16);
                    132: 
                    133:                if(ifname)
                    134:                        strlcpy(pcr.rule.ifname, ifname, IFNAMSIZ);
                    135: 
                    136:                pcr.action = PF_CHANGE_GET_TICKET;
                    137:                if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0) {
                    138:                        syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
                    139:                        return -1;
                    140:                } else {
                    141:                        pcr.action = PF_CHANGE_ADD_TAIL;
                    142:                        if(ioctl(dev, DIOCCHANGERULE, &pcr) < 0) {
                    143:                                syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_ADD_TAIL: %m");
                    144:                                return -1;
                    145:                        }
                    146:                }
                    147:        }
                    148: 
                    149:        if(++next_uid >= 65535) {
                    150:                next_uid = 1;
                    151:        }
                    152:        return uid;
                    153: }
                    154: 
                    155: int delete_pinhole(unsigned short uid)
                    156: {
                    157:        int i, n;
                    158:        struct pfioc_rule pr;
                    159:        char label_start[PF_RULE_LABEL_SIZE];
                    160:        char tmp_label[PF_RULE_LABEL_SIZE];
                    161: 
                    162:        if(dev<0) {
                    163:                syslog(LOG_ERR, "pf device is not open");
                    164:                return -1;
                    165:        }
                    166:        snprintf(label_start, sizeof(label_start),
                    167:                 "pinhole-%hu", uid);
                    168:        memset(&pr, 0, sizeof(pr));
                    169:        strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
                    170: #ifndef PF_NEWSTYLE
                    171:        pr.rule.action = PF_PASS;
                    172: #endif
                    173:        if(ioctl(dev, DIOCGETRULES, &pr) < 0) {
                    174:                syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
                    175:                return -1;
                    176:        }
                    177:        n = pr.nr;
                    178:        for(i=0; i<n; i++) {
                    179:                pr.nr = i;
                    180:                if(ioctl(dev, DIOCGETRULE, &pr) < 0) {
                    181:                        syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
                    182:                        return -1;
                    183:                }
                    184:                strlcpy(tmp_label, pr.rule.label, sizeof(tmp_label));
                    185:                strtok(tmp_label, " ");
                    186:                if(0 == strcmp(tmp_label, label_start)) {
                    187:                        pr.action = PF_CHANGE_GET_TICKET;
                    188:                        if(ioctl(dev, DIOCCHANGERULE, &pr) < 0) {
                    189:                                syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
                    190:                                return -1;
                    191:                        }
                    192:                        pr.action = PF_CHANGE_REMOVE;
                    193:                        pr.nr = i;
                    194:                        if(ioctl(dev, DIOCCHANGERULE, &pr) < 0) {
                    195:                                syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m");
                    196:                                return -1;
                    197:                        }
                    198:                        return 0;
                    199:                }
                    200:        }
                    201:        /* not found */
                    202:        return -2;
                    203: }
                    204: 
                    205: int
                    206: get_pinhole_info(unsigned short uid,
                    207:                  char * rem_host, int rem_hostlen, unsigned short * rem_port,
                    208:                  char * int_client, int int_clientlen, unsigned short * int_port,
                    209:                  int * proto, unsigned int * timestamp,
                    210:                  u_int64_t * packets, u_int64_t * bytes)
                    211: {
                    212:        int i, n;
                    213:        struct pfioc_rule pr;
                    214:        char label_start[PF_RULE_LABEL_SIZE];
                    215:        char tmp_label[PF_RULE_LABEL_SIZE];
                    216:        char * p;
                    217: 
                    218:        if(dev<0) {
                    219:                syslog(LOG_ERR, "pf device is not open");
                    220:                return -1;
                    221:        }
                    222:        snprintf(label_start, sizeof(label_start),
                    223:                 "pinhole-%hu", uid);
                    224:        memset(&pr, 0, sizeof(pr));
                    225:        strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
                    226: #ifndef PF_NEWSTYLE
                    227:        pr.rule.action = PF_PASS;
                    228: #endif
                    229:        if(ioctl(dev, DIOCGETRULES, &pr) < 0) {
                    230:                syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
                    231:                return -1;
                    232:        }
                    233:        n = pr.nr;
                    234:        for(i=0; i<n; i++) {
                    235:                pr.nr = i;
                    236:                if(ioctl(dev, DIOCGETRULE, &pr) < 0) {
                    237:                        syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
                    238:                        return -1;
                    239:                }
                    240:                strlcpy(tmp_label, pr.rule.label, sizeof(tmp_label));
                    241:                p = tmp_label;
                    242:                strsep(&p, " ");
                    243:                if(0 == strcmp(tmp_label, label_start)) {
                    244:                        if(rem_host && (inet_ntop(AF_INET6, &pr.rule.src.addr.v.a.addr.v6, rem_host, rem_hostlen) == NULL)) {
                    245:                                return -1;
                    246:                        }
                    247:                        if(rem_port)
                    248:                                *rem_port = ntohs(pr.rule.src.port[0]);
                    249:                        if(int_client && (inet_ntop(AF_INET6, &pr.rule.dst.addr.v.a.addr.v6, int_client, int_clientlen) == NULL)) {
                    250:                                return -1;
                    251:                        }
                    252:                        if(int_port)
                    253:                                *int_port = ntohs(pr.rule.dst.port[0]);
                    254:                        if(proto)
                    255:                                *proto = pr.rule.proto;
                    256:                        if(timestamp)
                    257:                                sscanf(p, "ts-%u", timestamp);
                    258: #ifdef PFRULE_INOUT_COUNTS
                    259:                        if(packets)
                    260:                                *packets = pr.rule.packets[0] + pr.rule.packets[1];
                    261:                        if(bytes)
                    262:                                *bytes = pr.rule.bytes[0] + pr.rule.bytes[1];
                    263: #else
                    264:                        if(packets)
                    265:                                *packets = pr.rule.packets;
                    266:                        if(bytes)
                    267:                                *bytes = pr.rule.bytes;
                    268: #endif
                    269:                        return 0;
                    270:                }
                    271:        }
                    272:        /* not found */
                    273:        return -2;
                    274: }
                    275: 
                    276: int update_pinhole(unsigned short uid, unsigned int timestamp)
                    277: {
                    278:        /* TODO :
                    279:         * As it is not possible to change rule label, we should :
                    280:         * 1 - delete
                    281:         * 2 - Add new
                    282:         * the stats of the rule will then be reset :( */
                    283:        return -42; /* not implemented */
                    284: }
                    285: 
                    286: /* return the number of rules removed
                    287:  * or a negative integer in case of error */
                    288: int clean_pinhole_list(unsigned int * next_timestamp)
                    289: {
                    290:        int i;
                    291:        struct pfioc_rule pr;
                    292:        time_t current_time;
                    293:        unsigned int ts;
                    294:        int uid;
                    295:        unsigned int min_ts = UINT_MAX;
                    296:        int min_uid = INT_MAX, max_uid = -1;
                    297:        int n = 0;
                    298: 
                    299:        if(dev<0) {
                    300:                syslog(LOG_ERR, "pf device is not open");
                    301:                return -1;
                    302:        }
                    303:        current_time = time(NULL);
                    304:        memset(&pr, 0, sizeof(pr));
                    305:        strlcpy(pr.anchor, anchor_name, MAXPATHLEN);
                    306: #ifndef PF_NEWSTYLE
                    307:        pr.rule.action = PF_PASS;
                    308: #endif
                    309:        if(ioctl(dev, DIOCGETRULES, &pr) < 0) {
                    310:                syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
                    311:                return -1;
                    312:        }
                    313:        for(i = pr.nr - 1; i >= 0; i--) {
                    314:                pr.nr = i;
                    315:                if(ioctl(dev, DIOCGETRULE, &pr) < 0) {
                    316:                        syslog(LOG_ERR, "ioctl(dev, DIOCGETRULE): %m");
                    317:                        return -1;
                    318:                }
                    319:                if(sscanf(pr.rule.label, PINEHOLE_LABEL_FORMAT, &uid, &ts) != 2) {
                    320:                        syslog(LOG_INFO, "rule with label '%s' is not a IGD pinhole", pr.rule.label);
                    321:                        continue;
                    322:                }
                    323:                if(ts <= (unsigned int)current_time) {
                    324:                        syslog(LOG_INFO, "removing expired pinhole '%s'", pr.rule.label);
                    325:                        pr.action = PF_CHANGE_GET_TICKET;
                    326:                        if(ioctl(dev, DIOCCHANGERULE, &pr) < 0) {
                    327:                                syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_GET_TICKET: %m");
                    328:                                return -1;
                    329:                        }
                    330:                        pr.action = PF_CHANGE_REMOVE;
                    331:                        pr.nr = i;
                    332:                        if(ioctl(dev, DIOCCHANGERULE, &pr) < 0) {
                    333:                                syslog(LOG_ERR, "ioctl(dev, DIOCCHANGERULE, ...) PF_CHANGE_REMOVE: %m");
                    334:                                return -1;
                    335:                        }
                    336:                        n++;
                    337: #ifndef PF_NEWSTYLE
                    338:                        pr.rule.action = PF_PASS;
                    339: #endif
                    340:                        if(ioctl(dev, DIOCGETRULES, &pr) < 0) {
                    341:                                syslog(LOG_ERR, "ioctl(dev, DIOCGETRULES, ...): %m");
                    342:                                return -1;
                    343:                        }
                    344:                } else {
                    345:                        if(uid > max_uid)
                    346:                                max_uid = uid;
                    347:                        else if(uid < min_uid)
                    348:                                min_uid = uid;
                    349:                        if(ts < min_ts)
                    350:                                min_ts = ts;
                    351:                }
                    352:        }
                    353:        if(next_timestamp && (min_ts != UINT_MAX))
                    354:                *next_timestamp = min_ts;
                    355:        if(max_uid > 0) {
                    356:                if(((min_uid - 32000) <= next_uid) && (next_uid <= max_uid)) {
                    357:                        next_uid = max_uid + 1;
                    358:                }
                    359:                if(next_uid >= 65535) {
                    360:                        next_uid = 1;
                    361:                }
                    362:        }
                    363:        return n;       /* number of rules removed */
                    364: }
                    365: 
                    366: #endif /* ENABLE_IPV6 */
                    367: 

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