Annotation of embedaddon/miniupnpd/netfilter/iptcrdr.c, revision 1.1

1.1     ! misho       1: /* $Id: iptcrdr.c,v 1.33 2010/09/27 09:17:59 nanard Exp $ */
        !             2: /* MiniUPnP project
        !             3:  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
        !             4:  * (c) 2006-2008 Thomas Bernard
        !             5:  * This software is subject to the conditions detailed
        !             6:  * in the LICENCE file provided within the distribution */
        !             7: #include <stdio.h>
        !             8: #include <stdlib.h>
        !             9: #include <string.h>
        !            10: #include <syslog.h>
        !            11: #include <sys/errno.h>
        !            12: #include <sys/socket.h>
        !            13: #include <netinet/in.h>
        !            14: #include <arpa/inet.h>
        !            15: #include <dlfcn.h>
        !            16: #include <libiptc/libiptc.h>
        !            17: #include <iptables.h>
        !            18: 
        !            19: #include <linux/version.h>
        !            20: 
        !            21: #if IPTABLES_143
        !            22: /* IPTABLES API version >= 1.4.3 */
        !            23: #include <net/netfilter/nf_nat.h>
        !            24: #define ip_nat_multi_range     nf_nat_multi_range
        !            25: #define ip_nat_range           nf_nat_range
        !            26: #define IPTC_HANDLE            struct iptc_handle *
        !            27: #else
        !            28: /* IPTABLES API version < 1.4.3 */
        !            29: #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
        !            30: #include <linux/netfilter_ipv4/ip_nat.h>
        !            31: #else
        !            32: #include <linux/netfilter/nf_nat.h>
        !            33: #endif
        !            34: #define IPTC_HANDLE            iptc_handle_t
        !            35: #endif
        !            36: 
        !            37: #include "iptcrdr.h"
        !            38: #include "../upnpglobalvars.h"
        !            39: 
        !            40: /* dummy init and shutdown functions */
        !            41: int init_redirect(void)
        !            42: {
        !            43:        return 0;
        !            44: }
        !            45: 
        !            46: void shutdown_redirect(void)
        !            47: {
        !            48:        return;
        !            49: }
        !            50: 
        !            51: /* convert an ip address to string */
        !            52: static int snprintip(char * dst, size_t size, uint32_t ip)
        !            53: {
        !            54:        return snprintf(dst, size,
        !            55:               "%u.%u.%u.%u", ip >> 24, (ip >> 16) & 0xff,
        !            56:               (ip >> 8) & 0xff, ip & 0xff);
        !            57: }
        !            58: 
        !            59: /* netfilter cannot store redirection descriptions, so we use our
        !            60:  * own structure to store them */
        !            61: struct rdr_desc {
        !            62:        struct rdr_desc * next;
        !            63:        unsigned short eport;
        !            64:        short proto;
        !            65:        char str[];
        !            66: };
        !            67: 
        !            68: /* pointer to the chained list where descriptions are stored */
        !            69: static struct rdr_desc * rdr_desc_list = 0;
        !            70: 
        !            71: static void
        !            72: add_redirect_desc(unsigned short eport, int proto, const char * desc)
        !            73: {
        !            74:        struct rdr_desc * p;
        !            75:        size_t l;
        !            76: /*     if(desc)
        !            77:        {*/
        !            78:                if ((l = strlen(desc) + 1) == 1) l = 5;
        !            79:                p = malloc(sizeof(struct rdr_desc) + l);
        !            80:                if(p)
        !            81:                {
        !            82:                        p->next = rdr_desc_list;
        !            83:                        p->eport = eport;
        !            84:                        p->proto = (short)proto;
        !            85:                        if(desc) memcpy(p->str, desc, l); else memcpy(p->str, "upnp", 4);
        !            86:                        rdr_desc_list = p;
        !            87:                }
        !            88: /*     }*/
        !            89: }
        !            90: 
        !            91: static void
        !            92: del_redirect_desc(unsigned short eport, int proto)
        !            93: {
        !            94:        struct rdr_desc * p, * last;
        !            95:        p = rdr_desc_list;
        !            96:        last = 0;
        !            97:        while(p)
        !            98:        {
        !            99:                if(p->eport == eport && p->proto == proto)
        !           100:                {
        !           101:                        if(!last)
        !           102:                                rdr_desc_list = p->next;
        !           103:                        else
        !           104:                                last->next = p->next;
        !           105:                        free(p);
        !           106:                        return;
        !           107:                }
        !           108:                last = p;
        !           109:                p = p->next;
        !           110:        }
        !           111: }
        !           112: 
        !           113: static void
        !           114: get_redirect_desc(unsigned short eport, int proto,
        !           115:                   char * desc, int desclen)
        !           116: {
        !           117:        struct rdr_desc * p;
        !           118:        if(!desc || (desclen == 0))
        !           119:                return;
        !           120:        for(p = rdr_desc_list; p; p = p->next)
        !           121:        {
        !           122:                if(p->eport == eport && p->proto == (short)proto)
        !           123:                {
        !           124:                        strncpy(desc, p->str, desclen);
        !           125:                        return;
        !           126:                }
        !           127:        }
        !           128:        /* if no description was found, return miniupnpd as default */
        !           129:        strncpy(desc, "miniupnpd", desclen);
        !           130: }
        !           131: 
        !           132: int
        !           133: get_redirect_desc_by_index(int index, unsigned short * eport, int * proto,
        !           134:                   char * desc, int desclen)
        !           135: {
        !           136:        int i = 0;
        !           137:        struct rdr_desc * p;
        !           138:        if(!desc || (desclen == 0))
        !           139:                return -1;
        !           140:        for(p = rdr_desc_list; p; p = p->next, i++)
        !           141:        {
        !           142:                if(i == index)
        !           143:                {
        !           144:                        *eport = p->eport;
        !           145:                        *proto = (int)p->proto;
        !           146:                        strncpy(desc, p->str, desclen);
        !           147:                        return 0;
        !           148:                }
        !           149:        }
        !           150:        return -1;
        !           151: }
        !           152: 
        !           153: /* add_redirect_rule2() */
        !           154: int
        !           155: add_redirect_rule2(const char * ifname, unsigned short eport,
        !           156:                    const char * iaddr, unsigned short iport, int proto,
        !           157:                                   const char * desc)
        !           158: {
        !           159:        int r = addnatrule(proto, eport, iaddr, iport);
        !           160:        if(r >= 0)
        !           161:                add_redirect_desc(eport, proto, desc);
        !           162:        return r;
        !           163: }
        !           164: 
        !           165: int
        !           166: add_filter_rule2(const char * ifname, const char * iaddr,
        !           167:                  unsigned short eport, unsigned short iport,
        !           168:                  int proto, const char * desc)
        !           169: {
        !           170:        return add_filter_rule(proto, iaddr, iport);
        !           171: }
        !           172: 
        !           173: /* get_redirect_rule() 
        !           174:  * returns -1 if the rule is not found */
        !           175: int
        !           176: get_redirect_rule(const char * ifname, unsigned short eport, int proto,
        !           177:                   char * iaddr, int iaddrlen, unsigned short * iport,
        !           178:                   char * desc, int desclen,
        !           179:                   u_int64_t * packets, u_int64_t * bytes)
        !           180: {
        !           181:        int r = -1;
        !           182:        IPTC_HANDLE h;
        !           183:        const struct ipt_entry * e;
        !           184:        const struct ipt_entry_target * target;
        !           185:        const struct ip_nat_multi_range * mr;
        !           186:        const struct ipt_entry_match *match;
        !           187: 
        !           188:        h = iptc_init("nat");
        !           189:        if(!h)
        !           190:        {
        !           191:                syslog(LOG_ERR, "get_redirect_rule() : "
        !           192:                                "iptc_init() failed : %s",
        !           193:                       iptc_strerror(errno));
        !           194:                return -1;
        !           195:        }
        !           196:        if(!iptc_is_chain(miniupnpd_nat_chain, h))
        !           197:        {
        !           198:                syslog(LOG_ERR, "chain %s not found", miniupnpd_nat_chain);
        !           199:        }
        !           200:        else
        !           201:        {
        !           202: #ifdef IPTABLES_143
        !           203:                for(e = iptc_first_rule(miniupnpd_nat_chain, h);
        !           204:                    e;
        !           205:                        e = iptc_next_rule(e, h))
        !           206: #else
        !           207:                for(e = iptc_first_rule(miniupnpd_nat_chain, &h);
        !           208:                    e;
        !           209:                        e = iptc_next_rule(e, &h))
        !           210: #endif
        !           211:                {
        !           212:                        if(proto==e->ip.proto)
        !           213:                        {
        !           214:                                match = (const struct ipt_entry_match *)&e->elems;
        !           215:                                if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
        !           216:                                {
        !           217:                                        const struct ipt_tcp * info;
        !           218:                                        info = (const struct ipt_tcp *)match->data;
        !           219:                                        if(eport != info->dpts[0])
        !           220:                                                continue;
        !           221:                                }
        !           222:                                else
        !           223:                                {
        !           224:                                        const struct ipt_udp * info;
        !           225:                                        info = (const struct ipt_udp *)match->data;
        !           226:                                        if(eport != info->dpts[0])
        !           227:                                                continue;
        !           228:                                }
        !           229:                                target = (void *)e + e->target_offset;
        !           230:                                //target = ipt_get_target(e);
        !           231:                                mr = (const struct ip_nat_multi_range *)&target->data[0];
        !           232:                                snprintip(iaddr, iaddrlen, ntohl(mr->range[0].min_ip));
        !           233:                                *iport = ntohs(mr->range[0].min.all);
        !           234:                                /*if(desc)
        !           235:                                        strncpy(desc, "miniupnpd", desclen);*/
        !           236:                                get_redirect_desc(eport, proto, desc, desclen);
        !           237:                                if(packets)
        !           238:                                        *packets = e->counters.pcnt;
        !           239:                                if(bytes)
        !           240:                                        *bytes = e->counters.bcnt;
        !           241:                                r = 0;
        !           242:                                break;
        !           243:                        }
        !           244:                }
        !           245:        }
        !           246:        if(h)
        !           247: #ifdef IPTABLES_143
        !           248:                iptc_free(h);
        !           249: #else
        !           250:                iptc_free(&h);
        !           251: #endif
        !           252:        return r;
        !           253: }
        !           254: 
        !           255: /* get_redirect_rule_by_index() 
        !           256:  * return -1 when the rule was not found */
        !           257: int
        !           258: get_redirect_rule_by_index(int index,
        !           259:                            char * ifname, unsigned short * eport,
        !           260:                            char * iaddr, int iaddrlen, unsigned short * iport,
        !           261:                            int * proto, char * desc, int desclen,
        !           262:                            u_int64_t * packets, u_int64_t * bytes)
        !           263: {
        !           264:        int r = -1;
        !           265:        r = get_redirect_desc_by_index(index, eport, proto, desc, desclen);
        !           266:        if (r==0)
        !           267:                r = get_redirect_rule(ifname, *eport, *proto, iaddr, iaddrlen, iport,
        !           268:                                      0, 0, packets, bytes);
        !           269: #if 0
        !           270:        int i = 0;
        !           271:        IPTC_HANDLE h;
        !           272:        const struct ipt_entry * e;
        !           273:        const struct ipt_entry_target * target;
        !           274:        const struct ip_nat_multi_range * mr;
        !           275:        const struct ipt_entry_match *match;
        !           276: 
        !           277:        h = iptc_init("nat");
        !           278:        if(!h)
        !           279:        {
        !           280:                syslog(LOG_ERR, "get_redirect_rule_by_index() : "
        !           281:                                "iptc_init() failed : %s",
        !           282:                       iptc_strerror(errno));
        !           283:                return -1;
        !           284:        }
        !           285:        if(!iptc_is_chain(miniupnpd_nat_chain, h))
        !           286:        {
        !           287:                syslog(LOG_ERR, "chain %s not found", miniupnpd_nat_chain);
        !           288:        }
        !           289:        else
        !           290:        {
        !           291: #ifdef IPTABLES_143
        !           292:                for(e = iptc_first_rule(miniupnpd_nat_chain, h);
        !           293:                    e;
        !           294:                        e = iptc_next_rule(e, h))
        !           295: #else
        !           296:                for(e = iptc_first_rule(miniupnpd_nat_chain, &h);
        !           297:                    e;
        !           298:                        e = iptc_next_rule(e, &h))
        !           299: #endif
        !           300:                {
        !           301:                        if(i==index)
        !           302:                        {
        !           303:                                *proto = e->ip.proto;
        !           304:                                match = (const struct ipt_entry_match *)&e->elems;
        !           305:                                if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
        !           306:                                {
        !           307:                                        const struct ipt_tcp * info;
        !           308:                                        info = (const struct ipt_tcp *)match->data;
        !           309:                                        *eport = info->dpts[0];
        !           310:                                }
        !           311:                                else
        !           312:                                {
        !           313:                                        const struct ipt_udp * info;
        !           314:                                        info = (const struct ipt_udp *)match->data;
        !           315:                                        *eport = info->dpts[0];
        !           316:                                }
        !           317:                                target = (void *)e + e->target_offset;
        !           318:                                mr = (const struct ip_nat_multi_range *)&target->data[0];
        !           319:                                snprintip(iaddr, iaddrlen, ntohl(mr->range[0].min_ip));
        !           320:                                *iport = ntohs(mr->range[0].min.all);
        !           321:                 /*if(desc)
        !           322:                                    strncpy(desc, "miniupnpd", desclen);*/
        !           323:                                get_redirect_desc(*eport, *proto, desc, desclen);
        !           324:                                if(packets)
        !           325:                                        *packets = e->counters.pcnt;
        !           326:                                if(bytes)
        !           327:                                        *bytes = e->counters.bcnt;
        !           328:                                r = 0;
        !           329:                                break;
        !           330:                        }
        !           331:                        i++;
        !           332:                }
        !           333:        }
        !           334:        if(h)
        !           335: #ifdef IPTABLES_143
        !           336:                iptc_free(h);
        !           337: #else
        !           338:                iptc_free(&h);
        !           339: #endif
        !           340: #endif /*0*/
        !           341:        return r;
        !           342: }
        !           343: 
        !           344: /* delete_rule_and_commit() :
        !           345:  * subfunction used in delete_redirect_and_filter_rules() */
        !           346: int
        !           347: delete_rule_and_commit(const char * table,
        !           348:                const char * miniupnpd_chain,
        !           349:                unsigned short eport, int proto,
        !           350:                const char * logcaller)
        !           351: {
        !           352:        int r = -1;
        !           353:        unsigned index = 0;
        !           354:        unsigned i = 0;
        !           355:        IPTC_HANDLE h;
        !           356:        const struct ipt_entry * e;
        !           357:        const struct ipt_entry_match *match;
        !           358: 
        !           359:        h = iptc_init(table);
        !           360:        if(!h)
        !           361:        {
        !           362:                syslog(LOG_ERR, "get_index_rules() : "
        !           363:                                "iptc_init(%s) failed : %s",
        !           364:                       table,
        !           365:                       iptc_strerror(errno));
        !           366:                return -1;
        !           367:        }
        !           368:        if(!iptc_is_chain(miniupnpd_chain, h))
        !           369:        {
        !           370:                syslog(LOG_ERR, "chain %s not found", miniupnpd_chain);
        !           371:        }
        !           372:        else
        !           373:        {
        !           374: #ifdef IPTABLES_143
        !           375:                for(e = iptc_first_rule(miniupnpd_chain, h);
        !           376:                    e;
        !           377:                        e = iptc_next_rule(e, h), i++)
        !           378: #else
        !           379:                for(e = iptc_first_rule(miniupnpd_chain, &h);
        !           380:                    e;
        !           381:                        e = iptc_next_rule(e, &h), i++)
        !           382: #endif
        !           383:                {
        !           384:                        if(proto==e->ip.proto)
        !           385:                        {
        !           386:                                match = (const struct ipt_entry_match *)&e->elems;
        !           387:                                if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
        !           388:                                {
        !           389:                                        const struct ipt_tcp * info;
        !           390:                                        info = (const struct ipt_tcp *)match->data;
        !           391:                                        if(eport != info->dpts[0])
        !           392:                                                continue;
        !           393:                                }
        !           394:                                else
        !           395:                                {
        !           396:                                        const struct ipt_udp * info;
        !           397:                                        info = (const struct ipt_udp *)match->data;
        !           398:                                        if(eport != info->dpts[0])
        !           399:                                                continue;
        !           400:                                }
        !           401:                                r = 0;
        !           402:                                index = i;
        !           403:                                break;
        !           404:                        }
        !           405:                }
        !           406:        }
        !           407:        if(h)
        !           408: #ifdef IPTABLES_143
        !           409:                iptc_free(h);
        !           410: #else
        !           411:                iptc_free(&h);
        !           412: #endif
        !           413:        if ((r == 0) && (h = iptc_init(table))) {
        !           414:                syslog(LOG_INFO, "Trying to delete rules at index %u", index);
        !           415:                /* Now delete both rules */
        !           416: #ifdef IPTABLES_143
        !           417:        if(!iptc_delete_num_entry(miniupnpd_chain, index, h))
        !           418: #else
        !           419:        if(!iptc_delete_num_entry(miniupnpd_chain, index, &h))
        !           420: #endif
        !           421:        {
        !           422:                syslog(LOG_ERR, "%s() : iptc_delete_num_entry(): %s\n",
        !           423:                   logcaller, iptc_strerror(errno));
        !           424:                r = -1;
        !           425:        }
        !           426: #ifdef IPTABLES_143
        !           427:        else if(!iptc_commit(h))
        !           428: #else
        !           429:        else if(!iptc_commit(&h))
        !           430: #endif
        !           431:        {
        !           432:                syslog(LOG_ERR, "%s() : iptc_commit(): %s\n",
        !           433:                   logcaller, iptc_strerror(errno));
        !           434:                r = -1;
        !           435:        }
        !           436:        if(h)
        !           437: #ifdef IPTABLES_143
        !           438:                iptc_free(h);
        !           439: #else
        !           440:                iptc_free(&h);
        !           441: #endif
        !           442:        }
        !           443:        return r;
        !           444: }
        !           445: 
        !           446: /* delete_redirect_and_filter_rules()
        !           447:  */
        !           448: int
        !           449: delete_redirect_and_filter_rules(unsigned short eport, int proto)
        !           450: {
        !           451:        int r = -1;
        !           452:        if ((r = delete_rule_and_commit("nat", miniupnpd_nat_chain, eport, proto, "delete_redirect_rule") &&
        !           453:            delete_rule_and_commit("filter", miniupnpd_forward_chain, eport, proto, "delete_filter_rule")) == 0)
        !           454:                del_redirect_desc(eport, proto);
        !           455:        return r;
        !           456: }
        !           457: 
        !           458: /* ==================================== */
        !           459: /* TODO : add the -m state --state NEW,ESTABLISHED,RELATED 
        !           460:  * only for the filter rule */
        !           461: static struct ipt_entry_match *
        !           462: get_tcp_match(unsigned short dport)
        !           463: {
        !           464:        struct ipt_entry_match *match;
        !           465:        struct ipt_tcp * tcpinfo;
        !           466:        size_t size;
        !           467:        size =   IPT_ALIGN(sizeof(struct ipt_entry_match))
        !           468:               + IPT_ALIGN(sizeof(struct ipt_tcp));
        !           469:        match = calloc(1, size);
        !           470:        match->u.match_size = size;
        !           471:        strncpy(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN);
        !           472:        tcpinfo = (struct ipt_tcp *)match->data;
        !           473:        tcpinfo->spts[0] = 0;           /* all source ports */
        !           474:        tcpinfo->spts[1] = 0xFFFF;
        !           475:        tcpinfo->dpts[0] = dport;       /* specified destination port */
        !           476:        tcpinfo->dpts[1] = dport;
        !           477:        return match;
        !           478: }
        !           479: 
        !           480: static struct ipt_entry_match *
        !           481: get_udp_match(unsigned short dport)
        !           482: {
        !           483:        struct ipt_entry_match *match;
        !           484:        struct ipt_udp * udpinfo;
        !           485:        size_t size;
        !           486:        size =   IPT_ALIGN(sizeof(struct ipt_entry_match))
        !           487:               + IPT_ALIGN(sizeof(struct ipt_udp));
        !           488:        match = calloc(1, size);
        !           489:        match->u.match_size = size;
        !           490:        strncpy(match->u.user.name, "udp", IPT_FUNCTION_MAXNAMELEN);
        !           491:        udpinfo = (struct ipt_udp *)match->data;
        !           492:        udpinfo->spts[0] = 0;           /* all source ports */
        !           493:        udpinfo->spts[1] = 0xFFFF;
        !           494:        udpinfo->dpts[0] = dport;       /* specified destination port */
        !           495:        udpinfo->dpts[1] = dport;
        !           496:        return match;
        !           497: }
        !           498: 
        !           499: static struct ipt_entry_target *
        !           500: get_dnat_target(const char * daddr, unsigned short dport)
        !           501: {
        !           502:        struct ipt_entry_target * target;
        !           503:        struct ip_nat_multi_range * mr;
        !           504:        struct ip_nat_range * range;
        !           505:        size_t size;
        !           506: 
        !           507:        size =   IPT_ALIGN(sizeof(struct ipt_entry_target))
        !           508:               + IPT_ALIGN(sizeof(struct ip_nat_multi_range));
        !           509:        target = calloc(1, size);
        !           510:        target->u.target_size = size;
        !           511:        strncpy(target->u.user.name, "DNAT", IPT_FUNCTION_MAXNAMELEN);
        !           512:        /* one ip_nat_range already included in ip_nat_multi_range */
        !           513:        mr = (struct ip_nat_multi_range *)&target->data[0];
        !           514:        mr->rangesize = 1;
        !           515:        range = &mr->range[0];
        !           516:        range->min_ip = range->max_ip = inet_addr(daddr);
        !           517:        range->flags |= IP_NAT_RANGE_MAP_IPS;
        !           518:        range->min.all = range->max.all = htons(dport);
        !           519:        range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
        !           520:        return target;
        !           521: }
        !           522: 
        !           523: /* iptc_init_verify_and_append()
        !           524:  * return 0 on success, -1 on failure */
        !           525: static int
        !           526: iptc_init_verify_and_append(const char * table, const char * miniupnpd_chain, struct ipt_entry * e,
        !           527:                             const char * logcaller)
        !           528: {
        !           529:        IPTC_HANDLE h;
        !           530:        h = iptc_init(table);
        !           531:        if(!h)
        !           532:        {
        !           533:                syslog(LOG_ERR, "%s : iptc_init() error : %s\n",
        !           534:                       logcaller, iptc_strerror(errno));
        !           535:                return -1;
        !           536:        }
        !           537:        if(!iptc_is_chain(miniupnpd_chain, h))
        !           538:        {
        !           539:                syslog(LOG_ERR, "%s : iptc_is_chain() error : %s\n",
        !           540:                       logcaller, iptc_strerror(errno));
        !           541:                if(h)
        !           542: #ifdef IPTABLES_143
        !           543:                        iptc_free(h);
        !           544: #else
        !           545:                        iptc_free(&h);
        !           546: #endif
        !           547:                return -1;
        !           548:        }
        !           549:        /* iptc_insert_entry(miniupnpd_chain, e, n, h/&h) could also be used */
        !           550: #ifdef IPTABLES_143
        !           551:        if(!iptc_append_entry(miniupnpd_chain, e, h))
        !           552: #else
        !           553:        if(!iptc_append_entry(miniupnpd_chain, e, &h))
        !           554: #endif
        !           555:        {
        !           556:                syslog(LOG_ERR, "%s : iptc_append_entry() error : %s\n",
        !           557:                       logcaller, iptc_strerror(errno));
        !           558:                if(h)
        !           559: #ifdef IPTABLES_143
        !           560:                        iptc_free(h);
        !           561: #else
        !           562:                        iptc_free(&h);
        !           563: #endif
        !           564:                return -1;
        !           565:        }
        !           566: #ifdef IPTABLES_143
        !           567:        if(!iptc_commit(h))
        !           568: #else
        !           569:        if(!iptc_commit(&h))
        !           570: #endif
        !           571:        {
        !           572:                syslog(LOG_ERR, "%s : iptc_commit() error : %s\n",
        !           573:                       logcaller, iptc_strerror(errno));
        !           574:                if(h)
        !           575: #ifdef IPTABLES_143
        !           576:                        iptc_free(h);
        !           577: #else
        !           578:                        iptc_free(&h);
        !           579: #endif
        !           580:                return -1;
        !           581:        }
        !           582:        if(h)
        !           583: #ifdef IPTABLES_143
        !           584:                iptc_free(h);
        !           585: #else
        !           586:                iptc_free(&h);
        !           587: #endif
        !           588:        return 0;
        !           589: }
        !           590: 
        !           591: /* add nat rule 
        !           592:  * iptables -t nat -A MINIUPNPD -p proto --dport eport -j DNAT --to iaddr:iport
        !           593:  * */
        !           594: int
        !           595: addnatrule(int proto, unsigned short eport,
        !           596:            const char * iaddr, unsigned short iport)
        !           597: {
        !           598:        int r = 0;
        !           599:        struct ipt_entry * e;
        !           600:        struct ipt_entry_match *match = NULL;
        !           601:        struct ipt_entry_target *target = NULL;
        !           602: 
        !           603:        e = calloc(1, sizeof(struct ipt_entry));
        !           604:        e->ip.proto = proto;
        !           605:        if(proto == IPPROTO_TCP)
        !           606:        {
        !           607:                match = get_tcp_match(eport);
        !           608:        }
        !           609:        else
        !           610:        {
        !           611:                match = get_udp_match(eport);
        !           612:        }
        !           613:        e->nfcache = NFC_IP_DST_PT;
        !           614:        target = get_dnat_target(iaddr, iport);
        !           615:        e->nfcache |= NFC_UNKNOWN;
        !           616:        e = realloc(e, sizeof(struct ipt_entry)
        !           617:                       + match->u.match_size
        !           618:                                   + target->u.target_size);
        !           619:        memcpy(e->elems, match, match->u.match_size);
        !           620:        memcpy(e->elems + match->u.match_size, target, target->u.target_size);
        !           621:        e->target_offset = sizeof(struct ipt_entry)
        !           622:                           + match->u.match_size;
        !           623:        e->next_offset = sizeof(struct ipt_entry)
        !           624:                         + match->u.match_size
        !           625:                                         + target->u.target_size;
        !           626:        
        !           627:        r = iptc_init_verify_and_append("nat", miniupnpd_nat_chain, e, "addnatrule()");
        !           628:        free(target);
        !           629:        free(match);
        !           630:        free(e);
        !           631:        return r;
        !           632: }
        !           633: /* ================================= */
        !           634: static struct ipt_entry_target *
        !           635: get_accept_target(void)
        !           636: {
        !           637:        struct ipt_entry_target * target = NULL;
        !           638:        size_t size;
        !           639:        size =   IPT_ALIGN(sizeof(struct ipt_entry_target))
        !           640:               + IPT_ALIGN(sizeof(int));
        !           641:        target = calloc(1, size);
        !           642:        target->u.user.target_size = size;
        !           643:        strncpy(target->u.user.name, "ACCEPT", IPT_FUNCTION_MAXNAMELEN);
        !           644:        return target;
        !           645: }
        !           646: 
        !           647: /* add_filter_rule()
        !           648:  * */
        !           649: int
        !           650: add_filter_rule(int proto, const char * iaddr, unsigned short iport)
        !           651: {
        !           652:        int r = 0;
        !           653:        struct ipt_entry * e;
        !           654:        struct ipt_entry_match *match = NULL;
        !           655:        struct ipt_entry_target *target = NULL;
        !           656: 
        !           657:        e = calloc(1, sizeof(struct ipt_entry));
        !           658:        e->ip.proto = proto;
        !           659:        if(proto == IPPROTO_TCP)
        !           660:        {
        !           661:                match = get_tcp_match(iport);
        !           662:        }
        !           663:        else
        !           664:        {
        !           665:                match = get_udp_match(iport);
        !           666:        }
        !           667:        e->nfcache = NFC_IP_DST_PT;
        !           668:        e->ip.dst.s_addr = inet_addr(iaddr);
        !           669:        e->ip.dmsk.s_addr = INADDR_NONE;
        !           670:        target = get_accept_target();
        !           671:        e->nfcache |= NFC_UNKNOWN;
        !           672:        e = realloc(e, sizeof(struct ipt_entry)
        !           673:                       + match->u.match_size
        !           674:                                   + target->u.target_size);
        !           675:        memcpy(e->elems, match, match->u.match_size);
        !           676:        memcpy(e->elems + match->u.match_size, target, target->u.target_size);
        !           677:        e->target_offset = sizeof(struct ipt_entry)
        !           678:                           + match->u.match_size;
        !           679:        e->next_offset = sizeof(struct ipt_entry)
        !           680:                         + match->u.match_size
        !           681:                                         + target->u.target_size;
        !           682:        
        !           683:        r = iptc_init_verify_and_append("filter", miniupnpd_forward_chain, e, "add_filter_rule()");
        !           684:        free(target);
        !           685:        free(match);
        !           686:        free(e);
        !           687:        return r;
        !           688: }
        !           689: 
        !           690: /* ================================ */
        !           691: static int
        !           692: print_match(const struct ipt_entry_match *match)
        !           693: {
        !           694:        printf("match %s\n", match->u.user.name);
        !           695:        if(0 == strncmp(match->u.user.name, "tcp", IPT_FUNCTION_MAXNAMELEN))
        !           696:        {
        !           697:                struct ipt_tcp * tcpinfo;
        !           698:                tcpinfo = (struct ipt_tcp *)match->data;
        !           699:                printf("srcport = %hu:%hu dstport = %hu:%hu\n",
        !           700:                       tcpinfo->spts[0], tcpinfo->spts[1],
        !           701:                           tcpinfo->dpts[0], tcpinfo->dpts[1]);
        !           702:        }
        !           703:        else if(0 == strncmp(match->u.user.name, "udp", IPT_FUNCTION_MAXNAMELEN))
        !           704:        {
        !           705:                struct ipt_udp * udpinfo;
        !           706:                udpinfo = (struct ipt_udp *)match->data;
        !           707:                printf("srcport = %hu:%hu dstport = %hu:%hu\n",
        !           708:                       udpinfo->spts[0], udpinfo->spts[1],
        !           709:                           udpinfo->dpts[0], udpinfo->dpts[1]);
        !           710:        }
        !           711:        return 0;
        !           712: }
        !           713: 
        !           714: static void
        !           715: print_iface(const char * iface, const unsigned char * mask, int invert)
        !           716: {
        !           717:        unsigned i;
        !           718:        if(mask[0] == 0)
        !           719:                return;
        !           720:        if(invert)
        !           721:                printf("! ");
        !           722:        for(i=0; i<IFNAMSIZ; i++)
        !           723:        {
        !           724:                if(mask[i])
        !           725:                {
        !           726:                        if(iface[i])
        !           727:                                putchar(iface[i]);
        !           728:                }
        !           729:                else
        !           730:                {
        !           731:                        if(iface[i-1])
        !           732:                                putchar('+');
        !           733:                        break;
        !           734:                }
        !           735:        }
        !           736: }
        !           737: 
        !           738: static void
        !           739: printip(uint32_t ip)
        !           740: {
        !           741:        printf("%u.%u.%u.%u", ip >> 24, (ip >> 16) & 0xff,
        !           742:               (ip >> 8) & 0xff, ip & 0xff);
        !           743: }
        !           744: 
        !           745: /* for debug */
        !           746: /* read the "filter" and "nat" tables */
        !           747: int
        !           748: list_redirect_rule(const char * ifname)
        !           749: {
        !           750:        IPTC_HANDLE h;
        !           751:        const struct ipt_entry * e;
        !           752:        const struct ipt_entry_target * target;
        !           753:        const struct ip_nat_multi_range * mr;
        !           754:        const char * target_str;
        !           755: 
        !           756:        h = iptc_init("nat");
        !           757:        if(!h)
        !           758:        {
        !           759:                printf("iptc_init() error : %s\n", iptc_strerror(errno));
        !           760:                return -1;
        !           761:        }
        !           762:        if(!iptc_is_chain(miniupnpd_nat_chain, h))
        !           763:        {
        !           764:                printf("chain %s not found\n", miniupnpd_nat_chain);
        !           765: #ifdef IPTABLES_143
        !           766:                iptc_free(h);
        !           767: #else
        !           768:                iptc_free(&h);
        !           769: #endif
        !           770:                return -1;
        !           771:        }
        !           772: #ifdef IPTABLES_143
        !           773:        for(e = iptc_first_rule(miniupnpd_nat_chain, h);
        !           774:                e;
        !           775:                e = iptc_next_rule(e, h))
        !           776:        {
        !           777:                target_str = iptc_get_target(e, h);
        !           778: #else
        !           779:        for(e = iptc_first_rule(miniupnpd_nat_chain, &h);
        !           780:                e;
        !           781:                e = iptc_next_rule(e, &h))
        !           782:        {
        !           783:                target_str = iptc_get_target(e, &h);
        !           784: #endif
        !           785:                printf("===\n");
        !           786:                printf("src = %s%s/%s\n", (e->ip.invflags & IPT_INV_SRCIP)?"! ":"",
        !           787:                       inet_ntoa(e->ip.src), inet_ntoa(e->ip.smsk));
        !           788:                printf("dst = %s%s/%s\n", (e->ip.invflags & IPT_INV_DSTIP)?"! ":"",
        !           789:                       inet_ntoa(e->ip.dst), inet_ntoa(e->ip.dmsk));
        !           790:                /*printf("in_if = %s  out_if = %s\n", e->ip.iniface, e->ip.outiface);*/
        !           791:                printf("in_if = ");
        !           792:                print_iface(e->ip.iniface, e->ip.iniface_mask,
        !           793:                            e->ip.invflags & IPT_INV_VIA_IN);
        !           794:                printf(" out_if = ");
        !           795:                print_iface(e->ip.outiface, e->ip.outiface_mask,
        !           796:                            e->ip.invflags & IPT_INV_VIA_OUT);
        !           797:                printf("\n");
        !           798:                printf("ip.proto = %s%d\n", (e->ip.invflags & IPT_INV_PROTO)?"! ":"",
        !           799:                       e->ip.proto);
        !           800:                /* display matches stuff */
        !           801:                if(e->target_offset)
        !           802:                {
        !           803:                        IPT_MATCH_ITERATE(e, print_match);
        !           804:                        /*printf("\n");*/
        !           805:                }
        !           806:                printf("target = %s\n", target_str);
        !           807:                target = (void *)e + e->target_offset;
        !           808:                mr = (const struct ip_nat_multi_range *)&target->data[0];
        !           809:                printf("ips ");
        !           810:                printip(ntohl(mr->range[0].min_ip));
        !           811:                printf(" ");
        !           812:                printip(ntohl(mr->range[0].max_ip));
        !           813:                printf("\nports %hu %hu\n", ntohs(mr->range[0].min.all),
        !           814:                          ntohs(mr->range[0].max.all));
        !           815:                printf("flags = %x\n", mr->range[0].flags);
        !           816:        }
        !           817:        if(h)
        !           818: #ifdef IPTABLES_143
        !           819:                iptc_free(h);
        !           820: #else
        !           821:                iptc_free(&h);
        !           822: #endif
        !           823:        return 0;
        !           824: }
        !           825: 

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