Annotation of embedaddon/miniupnpd/netfilter/iptcrdr.c, revision 1.1.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>