Annotation of embedaddon/miniupnpd/pf/pfpinhole.c, revision 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>