Annotation of embedaddon/miniupnpd/miniupnpd.c, revision 1.1.1.3

1.1.1.3 ! misho       1: /* $Id: miniupnpd.c,v 1.173 2013/02/06 10:50:04 nanard Exp $ */
1.1       misho       2: /* MiniUPnP project
                      3:  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
1.1.1.3 ! misho       4:  * (c) 2006-2013 Thomas Bernard
1.1       misho       5:  * This software is subject to the conditions detailed
                      6:  * in the LICENCE file provided within the distribution */
                      7: 
                      8: #include "config.h"
                      9: 
                     10: /* Experimental support for NFQUEUE interfaces */
                     11: #ifdef ENABLE_NFQUEUE
                     12: /* apt-get install libnetfilter-queue-dev */
                     13: #include <netinet/ip.h>
                     14: #include <netinet/udp.h>
1.1.1.3 ! misho      15: #if 0
        !            16: #include <linux/netfilter_ipv4.h>  /* Defines verdicts (NF_ACCEPT, etc) */
        !            17: #endif
1.1       misho      18: #include <linux/netfilter.h>
                     19: #include <libnetfilter_queue/libnetfilter_queue.h>
                     20: #include <linux/netfilter/nfnetlink_queue.h>
                     21: #endif
                     22: 
                     23: #include <stdlib.h>
                     24: #include <unistd.h>
                     25: #include <string.h>
                     26: #include <stdio.h>
                     27: #include <ctype.h>
                     28: #include <sys/types.h>
                     29: #include <sys/socket.h>
                     30: #include <netinet/in.h>
                     31: #include <arpa/inet.h>
                     32: #include <fcntl.h>
                     33: #include <sys/file.h>
                     34: #include <syslog.h>
                     35: #include <sys/time.h>
                     36: #include <time.h>
                     37: #include <signal.h>
                     38: #include <errno.h>
                     39: #include <sys/param.h>
                     40: #if defined(sun)
                     41: #include <kstat.h>
                     42: #else
                     43: /* for BSD's sysctl */
                     44: #include <sys/sysctl.h>
                     45: #endif
                     46: 
                     47: /* unix sockets */
                     48: #ifdef USE_MINIUPNPDCTL
                     49: #include <sys/un.h>
                     50: #endif
                     51: 
1.1.1.3 ! misho      52: #include "macros.h"
1.1       misho      53: #include "upnpglobalvars.h"
                     54: #include "upnphttp.h"
                     55: #include "upnpdescgen.h"
                     56: #include "miniupnpdpath.h"
                     57: #include "getifaddr.h"
                     58: #include "upnpsoap.h"
                     59: #include "options.h"
                     60: #include "minissdp.h"
                     61: #include "upnpredirect.h"
1.1.1.3 ! misho      62: #include "upnppinhole.h"
1.1       misho      63: #include "miniupnpdtypes.h"
                     64: #include "daemonize.h"
                     65: #include "upnpevents.h"
                     66: #ifdef ENABLE_NATPMP
                     67: #include "natpmp.h"
                     68: #endif
                     69: #include "commonrdr.h"
1.1.1.2   misho      70: #include "upnputils.h"
                     71: #ifdef USE_IFACEWATCHER
                     72: #include "ifacewatcher.h"
                     73: #endif
1.1.1.3 ! misho      74: #ifdef ENABLE_6FC_SERVICE
        !            75: #ifdef USE_NETFILTER
        !            76: void init_iptpinhole(void);
        !            77: #endif
        !            78: #endif
1.1       misho      79: 
                     80: #ifndef DEFAULT_CONFIG
                     81: #define DEFAULT_CONFIG "/etc/miniupnpd.conf"
                     82: #endif
                     83: 
                     84: #ifdef USE_MINIUPNPDCTL
                     85: struct ctlelem {
                     86:        int socket;
                     87:        LIST_ENTRY(ctlelem) entries;
                     88: };
                     89: #endif
                     90: 
                     91: #ifdef ENABLE_NFQUEUE
                     92: /* globals */
                     93: static struct nfq_handle *nfqHandle;
                     94: static struct sockaddr_in ssdp;
                     95: 
                     96: /* prototypes */
                     97: static int nfqueue_cb( struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *data) ;
                     98: int identify_ip_protocol (char *payload);
                     99: int get_udp_dst_port (char *payload);
                    100: #endif
                    101: 
1.1.1.2   misho     102: /* variables used by signals */
1.1.1.3 ! misho     103: static volatile sig_atomic_t quitting = 0;
        !           104: volatile sig_atomic_t should_send_public_address_change_notif = 0;
1.1       misho     105: 
                    106: /* OpenAndConfHTTPSocket() :
                    107:  * setup the socket used to handle incoming HTTP connections. */
                    108: static int
                    109: OpenAndConfHTTPSocket(unsigned short port)
                    110: {
                    111:        int s;
                    112:        int i = 1;
1.1.1.2   misho     113: #ifdef ENABLE_IPV6
                    114:        struct sockaddr_in6 listenname;
                    115: #else
1.1       misho     116:        struct sockaddr_in listenname;
1.1.1.2   misho     117: #endif
                    118:        socklen_t listenname_len;
1.1       misho     119: 
1.1.1.2   misho     120:        if( (s = socket(
                    121: #ifdef ENABLE_IPV6
                    122:                        PF_INET6,
                    123: #else
                    124:                        PF_INET,
                    125: #endif
                    126:                        SOCK_STREAM, 0)) < 0)
1.1       misho     127:        {
                    128:                syslog(LOG_ERR, "socket(http): %m");
                    129:                return -1;
                    130:        }
                    131: 
                    132:        if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0)
                    133:        {
                    134:                syslog(LOG_WARNING, "setsockopt(http, SO_REUSEADDR): %m");
                    135:        }
1.1.1.2   misho     136: #if 0
                    137:        /* enable this to force IPV6 only for IPV6 socket.
                    138:         * see http://www.ietf.org/rfc/rfc3493.txt section 5.3 */
                    139:        if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &i, sizeof(i)) < 0)
                    140:        {
                    141:                syslog(LOG_WARNING, "setsockopt(http, IPV6_V6ONLY): %m");
                    142:        }
                    143: #endif
1.1       misho     144: 
1.1.1.3 ! misho     145:        if(!set_non_blocking(s))
        !           146:        {
        !           147:                syslog(LOG_WARNING, "set_non_blocking(http): %m");
        !           148:        }
        !           149: 
1.1.1.2   misho     150: #ifdef ENABLE_IPV6
                    151:        memset(&listenname, 0, sizeof(struct sockaddr_in6));
                    152:        listenname.sin6_family = AF_INET6;
                    153:        listenname.sin6_port = htons(port);
                    154:        listenname.sin6_addr = in6addr_any;
                    155:        listenname_len =  sizeof(struct sockaddr_in6);
                    156: #else
1.1       misho     157:        listenname.sin_family = AF_INET;
                    158:        listenname.sin_port = htons(port);
                    159:        listenname.sin_addr.s_addr = htonl(INADDR_ANY);
1.1.1.2   misho     160:        listenname_len =  sizeof(struct sockaddr_in);
                    161: #endif
1.1       misho     162: 
1.1.1.2   misho     163:        if(bind(s, (struct sockaddr *)&listenname, listenname_len) < 0)
1.1       misho     164:        {
                    165:                syslog(LOG_ERR, "bind(http): %m");
                    166:                close(s);
                    167:                return -1;
                    168:        }
                    169: 
1.1.1.2   misho     170:        if(listen(s, 5) < 0)
1.1       misho     171:        {
                    172:                syslog(LOG_ERR, "listen(http): %m");
                    173:                close(s);
                    174:                return -1;
                    175:        }
                    176: 
                    177:        return s;
                    178: }
                    179: #ifdef ENABLE_NFQUEUE
                    180: 
                    181: int identify_ip_protocol(char *payload) {
                    182:     return payload[9];
                    183: }
                    184: 
                    185: 
                    186: /*
                    187:  * This function returns the destination port of the captured packet UDP
                    188:  */
                    189: int get_udp_dst_port(char *payload) {
                    190:         char *pkt_data_ptr = NULL;
                    191:         pkt_data_ptr = payload + sizeof(struct ip);
                    192: 
                    193:     /* Cast the UDP Header from the raw packet */
                    194:     struct udphdr *udp = (struct udphdr *) pkt_data_ptr;
                    195: 
                    196:     /* get the dst port of the packet */
                    197:     return(ntohs(udp->dest));
                    198: 
                    199: }
                    200: static int
                    201: OpenAndConfNFqueue(){
                    202: 
                    203:         struct nfq_q_handle *myQueue;
                    204:         struct nfnl_handle *netlinkHandle;
                    205: 
                    206:         int fd = 0, e = 0;
                    207: 
                    208:        inet_pton(AF_INET, "239.255.255.250", &(ssdp.sin_addr));
                    209: 
1.1.1.3 ! misho     210:         /* Get a queue connection handle from the module */
1.1       misho     211:         if (!(nfqHandle = nfq_open())) {
                    212:                syslog(LOG_ERR, "Error in nfq_open(): %m");
                    213:                 return -1;
                    214:         }
                    215: 
1.1.1.3 ! misho     216:         /* Unbind the handler from processing any IP packets
        !           217:            Not totally sure why this is done, or if it's necessary... */
1.1       misho     218:         if ((e = nfq_unbind_pf(nfqHandle, AF_INET)) < 0) {
                    219:                syslog(LOG_ERR, "Error in nfq_unbind_pf(): %m");
                    220:                 return -1;
                    221:         }
                    222: 
1.1.1.3 ! misho     223:         /* Bind this handler to process IP packets... */
1.1       misho     224:         if (nfq_bind_pf(nfqHandle, AF_INET) < 0) {
                    225:                syslog(LOG_ERR, "Error in nfq_bind_pf(): %m");
                    226:                 return -1;
                    227:         }
                    228: 
1.1.1.3 ! misho     229:         /*      Install a callback on queue -Q */
1.1       misho     230:         if (!(myQueue = nfq_create_queue(nfqHandle,  nfqueue, &nfqueue_cb, NULL))) {
                    231:                syslog(LOG_ERR, "Error in nfq_create_queue(): %m");
                    232:                 return -1;
                    233:         }
                    234: 
1.1.1.3 ! misho     235:         /*      Turn on packet copy mode */
1.1       misho     236:         if (nfq_set_mode(myQueue, NFQNL_COPY_PACKET, 0xffff) < 0) {
                    237:                syslog(LOG_ERR, "Error setting packet copy mode (): %m");
                    238:                 return -1;
                    239:         }
                    240: 
                    241:         netlinkHandle = nfq_nfnlh(nfqHandle);
                    242:         fd = nfnl_fd(netlinkHandle);
                    243: 
                    244:        return fd;
                    245: 
                    246: }
                    247: 
                    248: 
                    249: static int nfqueue_cb(
                    250:                 struct nfq_q_handle *qh,
                    251:                 struct nfgenmsg *nfmsg,
                    252:                 struct nfq_data *nfa,
                    253:                 void *data) {
                    254: 
                    255:        char    *pkt;
                    256:        struct nfqnl_msg_packet_hdr *ph;
                    257:        ph = nfq_get_msg_packet_hdr(nfa);
                    258: 
                    259:        if ( ph ) {
                    260: 
                    261:                int id = 0, size = 0;
                    262:                id = ntohl(ph->packet_id);
                    263: 
                    264:                size = nfq_get_payload(nfa, &pkt);
                    265: 
                    266:                struct ip *iph = (struct ip *) pkt;
                    267: 
                    268:                int id_protocol = identify_ip_protocol(pkt);
                    269: 
                    270:                int dport = get_udp_dst_port(pkt);
                    271: 
                    272:                int x = sizeof (struct ip) + sizeof (struct udphdr);
1.1.1.3 ! misho     273: 
        !           274:                /* packets we are interested in are UDP multicast to 239.255.255.250:1900
1.1       misho     275:                 * and start with a data string M-SEARCH
                    276:                 */
1.1.1.3 ! misho     277:                if ( (dport == 1900) && (id_protocol == IPPROTO_UDP)
1.1       misho     278:                        && (ssdp.sin_addr.s_addr == iph->ip_dst.s_addr) ) {
1.1.1.3 ! misho     279: 
1.1       misho     280:                        /* get the index that the packet came in on */
                    281:                        u_int32_t idx = nfq_get_indev(nfa);
                    282:                        int i = 0;
                    283:                        for ( ;i < n_nfqix ; i++) {
                    284:                                if ( nfqix[i] == idx ) {
                    285: 
                    286:                                        struct udphdr *udp = (struct udphdr *) (pkt + sizeof(struct ip));
                    287: 
                    288:                                        char *dd = pkt + x;
1.1.1.3 ! misho     289: 
1.1       misho     290:                                        struct sockaddr_in sendername;
                    291:                                        sendername.sin_family = AF_INET;
                    292:                                        sendername.sin_port = udp->source;
                    293:                                        sendername.sin_addr.s_addr = iph->ip_src.s_addr;
                    294: 
                    295:                                        /* printf("pkt found %s\n",dd);*/
1.1.1.2   misho     296:                                        ProcessSSDPData (sudp, dd, size - x,
                    297:                                                         &sendername, (unsigned short) 5555);
1.1       misho     298:                                }
                    299:                        }
                    300:                }
1.1.1.3 ! misho     301: 
1.1       misho     302:                nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL);
                    303: 
                    304:        } else {
                    305:                syslog(LOG_ERR,"nfq_get_msg_packet_hdr failed");
1.1.1.3 ! misho     306:                return 1;
        !           307:                /* from nfqueue source: 0 = ok, >0 = soft error, <0 hard error */
1.1       misho     308:        }
                    309: 
                    310:        return 0;
                    311: }
                    312: 
                    313: static void ProcessNFQUEUE(int fd){
                    314:        char buf[4096];
                    315: 
                    316:        socklen_t len_r;
                    317:        struct sockaddr_in sendername;
                    318:        len_r = sizeof(struct sockaddr_in);
                    319: 
                    320:         int res = recvfrom(fd, buf, sizeof(buf), 0,
                    321:                        (struct sockaddr *)&sendername, &len_r);
                    322: 
                    323:        nfq_handle_packet(nfqHandle, buf, res);
                    324: }
                    325: #endif
                    326: 
                    327: /* Functions used to communicate with miniupnpdctl */
                    328: #ifdef USE_MINIUPNPDCTL
                    329: static int
                    330: OpenAndConfCtlUnixSocket(const char * path)
                    331: {
                    332:        struct sockaddr_un localun;
                    333:        int s;
                    334:        s = socket(AF_UNIX, SOCK_STREAM, 0);
                    335:        localun.sun_family = AF_UNIX;
                    336:        strncpy(localun.sun_path, path,
                    337:                  sizeof(localun.sun_path));
                    338:        if(bind(s, (struct sockaddr *)&localun,
                    339:                sizeof(struct sockaddr_un)) < 0)
                    340:        {
                    341:                syslog(LOG_ERR, "bind(sctl): %m");
                    342:                close(s);
                    343:                s = -1;
                    344:        }
                    345:        else if(listen(s, 5) < 0)
                    346:        {
                    347:                syslog(LOG_ERR, "listen(sctl): %m");
                    348:                close(s);
                    349:                s = -1;
                    350:        }
                    351:        return s;
                    352: }
                    353: 
                    354: static void
                    355: write_upnphttp_details(int fd, struct upnphttp * e)
                    356: {
                    357:        char buffer[256];
                    358:        int len;
                    359:        write(fd, "HTTP :\n", 7);
                    360:        while(e)
                    361:        {
                    362:                len = snprintf(buffer, sizeof(buffer),
                    363:                               "%d %d %s req_buf=%p(%dbytes) res_buf=%p(%dbytes alloc)\n",
                    364:                               e->socket, e->state, e->HttpVer,
                    365:                               e->req_buf, e->req_buflen,
                    366:                               e->res_buf, e->res_buf_alloclen);
                    367:                write(fd, buffer, len);
                    368:                e = e->entries.le_next;
                    369:        }
                    370: }
                    371: 
                    372: static void
                    373: write_ctlsockets_list(int fd, struct ctlelem * e)
                    374: {
                    375:        char buffer[256];
                    376:        int len;
                    377:        write(fd, "CTL :\n", 6);
                    378:        while(e)
                    379:        {
                    380:                len = snprintf(buffer, sizeof(buffer),
                    381:                               "struct ctlelem: socket=%d\n", e->socket);
                    382:                write(fd, buffer, len);
                    383:                e = e->entries.le_next;
                    384:        }
                    385: }
                    386: 
1.1.1.3 ! misho     387: #ifndef DISABLE_CONFIG_FILE
1.1       misho     388: static void
                    389: write_option_list(int fd)
                    390: {
                    391:        char buffer[256];
                    392:        int len;
1.1.1.3 ! misho     393:        unsigned int i;
1.1       misho     394:        write(fd, "Options :\n", 10);
                    395:        for(i=0; i<num_options; i++)
                    396:        {
                    397:                len = snprintf(buffer, sizeof(buffer),
                    398:                               "opt=%02d %s\n",
                    399:                               ary_options[i].id, ary_options[i].value);
                    400:                write(fd, buffer, len);
                    401:        }
                    402: }
1.1.1.3 ! misho     403: #endif
1.1       misho     404: 
                    405: static void
                    406: write_command_line(int fd, int argc, char * * argv)
                    407: {
                    408:        char buffer[256];
                    409:        int len;
                    410:        int i;
                    411:        write(fd, "Command Line :\n", 15);
                    412:        for(i=0; i<argc; i++)
                    413:        {
                    414:                len = snprintf(buffer, sizeof(buffer),
                    415:                               "argv[%02d]='%s'\n",
                    416:                                i, argv[i]);
                    417:                write(fd, buffer, len);
                    418:        }
                    419: }
                    420: 
                    421: #endif
                    422: 
1.1.1.3 ! misho     423: /* Handler for the SIGTERM signal (kill)
1.1       misho     424:  * SIGINT is also handled */
                    425: static void
                    426: sigterm(int sig)
                    427: {
1.1.1.3 ! misho     428:        UNUSED(sig);
        !           429:        /*int save_errno = errno; */
        !           430:        /*signal(sig, SIG_IGN);*/       /* Ignore this signal while we are quitting */
        !           431:        /* Note : isn't it useless ? */
1.1       misho     432: 
1.1.1.3 ! misho     433: #if 0
        !           434:        /* calling syslog() is forbidden in signal handler according to
        !           435:         * signal(3) */
1.1       misho     436:        syslog(LOG_NOTICE, "received signal %d, good-bye", sig);
1.1.1.3 ! misho     437: #endif
1.1       misho     438: 
                    439:        quitting = 1;
                    440:        /*errno = save_errno;*/
                    441: }
                    442: 
                    443: /* Handler for the SIGUSR1 signal indicating public IP address change. */
                    444: static void
                    445: sigusr1(int sig)
                    446: {
1.1.1.3 ! misho     447:        UNUSED(sig);
        !           448: #if 0
        !           449:        /* calling syslog() is forbidden in signal handler according to
        !           450:         * signal(3) */
1.1       misho     451:        syslog(LOG_INFO, "received signal %d, public ip address change", sig);
1.1.1.3 ! misho     452: #endif
1.1       misho     453: 
                    454:        should_send_public_address_change_notif = 1;
                    455: }
                    456: 
                    457: /* record the startup time, for returning uptime */
                    458: static void
                    459: set_startup_time(int sysuptime)
                    460: {
                    461:        startup_time = time(NULL);
                    462:        if(sysuptime)
                    463:        {
                    464:                /* use system uptime instead of daemon uptime */
                    465: #if defined(__linux__)
                    466:                char buff[64];
                    467:                int uptime = 0, fd;
                    468:                fd = open("/proc/uptime", O_RDONLY);
                    469:                if(fd < 0)
                    470:                {
                    471:                        syslog(LOG_ERR, "open(\"/proc/uptime\" : %m");
                    472:                }
                    473:                else
                    474:                {
                    475:                        memset(buff, 0, sizeof(buff));
                    476:                        if(read(fd, buff, sizeof(buff) - 1) < 0)
                    477:                        {
                    478:                                syslog(LOG_ERR, "read(\"/proc/uptime\" : %m");
                    479:                        }
                    480:                        else
                    481:                        {
                    482:                                uptime = atoi(buff);
                    483:                                syslog(LOG_INFO, "system uptime is %d seconds", uptime);
                    484:                        }
                    485:                        close(fd);
                    486:                        startup_time -= uptime;
                    487:                }
                    488: #elif defined(SOLARIS_KSTATS)
                    489:                kstat_ctl_t *kc;
                    490:                kc = kstat_open();
                    491:                if(kc != NULL)
                    492:                {
                    493:                        kstat_t *ksp;
                    494:                        ksp = kstat_lookup(kc, "unix", 0, "system_misc");
                    495:                        if(ksp && (kstat_read(kc, ksp, NULL) != -1))
                    496:                        {
                    497:                                void *ptr = kstat_data_lookup(ksp, "boot_time");
                    498:                                if(ptr)
                    499:                                        memcpy(&startup_time, ptr, sizeof(startup_time));
                    500:                                else
                    501:                                        syslog(LOG_ERR, "cannot find boot_time kstat");
                    502:                        }
                    503:                        else
                    504:                                syslog(LOG_ERR, "cannot open kstats for unix/0/system_misc: %m");
                    505:                        kstat_close(kc);
                    506:                }
                    507: #else
                    508:                struct timeval boottime;
                    509:                size_t size = sizeof(boottime);
                    510:                int name[2] = { CTL_KERN, KERN_BOOTTIME };
                    511:                if(sysctl(name, 2, &boottime, &size, NULL, 0) < 0)
                    512:                {
                    513:                        syslog(LOG_ERR, "sysctl(\"kern.boottime\") failed");
                    514:                }
                    515:                else
                    516:                {
                    517:                        startup_time = boottime.tv_sec;
                    518:                }
                    519: #endif
                    520:        }
                    521: }
                    522: 
                    523: /* structure containing variables used during "main loop"
                    524:  * that are filled during the init */
                    525: struct runtime_vars {
                    526:        /* LAN IP addresses for SSDP traffic and HTTP */
                    527:        /* moved to global vars */
                    528:        int port;       /* HTTP Port */
                    529:        int notify_interval;    /* seconds between SSDP announces */
                    530:        /* unused rules cleaning related variables : */
                    531:        int clean_ruleset_threshold;    /* threshold for removing unused rules */
                    532:        int clean_ruleset_interval;             /* (minimum) interval between checks */
                    533: };
                    534: 
                    535: /* parselanaddr()
                    536:  * parse address with mask
1.1.1.3 ! misho     537:  * ex: 192.168.1.1/24 or 192.168.1.1/255.255.255.0
1.1       misho     538:  * When MULTIPLE_EXTERNAL_IP is enabled, the ip address of the
                    539:  * external interface associated with the lan subnet follows.
                    540:  * ex : 192.168.1.1/24 81.21.41.11
                    541:  *
1.1.1.3 ! misho     542:  * Can also use the interface name (ie eth0)
        !           543:  *
        !           544:  * return value :
1.1       misho     545:  *    0 : ok
                    546:  *   -1 : error */
                    547: static int
                    548: parselanaddr(struct lan_addr_s * lan_addr, const char * str)
                    549: {
                    550:        const char * p;
                    551:        int n;
1.1.1.3 ! misho     552:        char tmp[16];
        !           553: 
        !           554:        memset(lan_addr, 0, sizeof(struct lan_addr_s));
1.1       misho     555:        p = str;
                    556:        while(*p && *p != '/' && !isspace(*p))
                    557:                p++;
                    558:        n = p - str;
1.1.1.3 ! misho     559:        if(!isdigit(str[0]) && n < (int)sizeof(lan_addr->ifname))
1.1       misho     560:        {
1.1.1.3 ! misho     561:                /* not starting with a digit : suppose it is an interface name */
        !           562:                memcpy(lan_addr->ifname, str, n);
        !           563:                lan_addr->ifname[n] = '\0';
        !           564:                if(getifaddr(lan_addr->ifname, lan_addr->str, sizeof(lan_addr->str)) < 0)
        !           565:                        goto parselan_error;
1.1       misho     566:        }
1.1.1.3 ! misho     567:        else
1.1       misho     568:        {
1.1.1.3 ! misho     569:                if(n>15)
        !           570:                        goto parselan_error;
        !           571:                memcpy(lan_addr->str, str, n);
        !           572:                lan_addr->str[n] = '\0';
1.1       misho     573:        }
                    574:        if(!inet_aton(lan_addr->str, &lan_addr->addr))
1.1.1.3 ! misho     575:                goto parselan_error;
        !           576:        if(*p == '/')
1.1       misho     577:        {
1.1.1.3 ! misho     578:                const char * q = ++p;
        !           579:                while(*p && isdigit(*p))
        !           580:                        p++;
        !           581:                if(*p=='.')
        !           582:                {
        !           583:                        while(*p && (*p=='.' || isdigit(*p)))
        !           584:                                p++;
        !           585:                        n = p - q;
        !           586:                        if(n>15)
        !           587:                                goto parselan_error;
        !           588:                        memcpy(tmp, q, n);
        !           589:                        tmp[n] = '\0';
        !           590:                        if(!inet_aton(tmp, &lan_addr->mask))
        !           591:                                goto parselan_error;
        !           592:                }
        !           593:                else
        !           594:                {
        !           595:                        int nbits = atoi(q);
        !           596:                        if(nbits > 32 || nbits < 0)
        !           597:                                goto parselan_error;
        !           598:                        lan_addr->mask.s_addr = htonl(nbits ? (0xffffffffu << (32 - nbits)) : 0);
        !           599:                }
        !           600:        }
        !           601:        else
        !           602:        {
        !           603:                /* by default, networks are /24 */
        !           604:                lan_addr->mask.s_addr = htonl(0xffffff00u);
1.1       misho     605:        }
                    606: #ifdef MULTIPLE_EXTERNAL_IP
                    607:        /* skip spaces */
                    608:        while(*p && isspace(*p))
                    609:                p++;
                    610:        if(*p) {
                    611:                /* parse the exteral ip address to associate with this subnet */
                    612:                n = 0;
                    613:                while(p[n] && !isspace(*p))
                    614:                        n++;
                    615:                if(n<=15) {
                    616:                        memcpy(lan_addr->ext_ip_str, p, n);
                    617:                        lan_addr->ext_ip_str[n] = '\0';
                    618:                        if(!inet_aton(lan_addr->ext_ip_str, &lan_addr->ext_ip_addr)) {
                    619:                                /* error */
                    620:                                fprintf(stderr, "Error parsing address : %s\n", lan_addr->ext_ip_str);
                    621:                        }
                    622:                }
                    623:        }
                    624: #endif
1.1.1.3 ! misho     625: #ifdef ENABLE_IPV6
        !           626:        if(lan_addr->ifname[0] != '\0')
        !           627:        {
        !           628:                lan_addr->index = if_nametoindex(lan_addr->ifname);
        !           629:                if(lan_addr->index == 0)
        !           630:                        fprintf(stderr, "Cannot get index for network interface %s",
        !           631:                                lan_addr->ifname);
        !           632:        }
        !           633: #endif
1.1       misho     634:        return 0;
1.1.1.3 ! misho     635: parselan_error:
        !           636:        fprintf(stderr, "Error parsing address/mask (or interface name) : %s\n",
        !           637:                str);
        !           638:        return -1;
1.1       misho     639: }
                    640: 
                    641: /* init phase :
                    642:  * 1) read configuration file
                    643:  * 2) read command line arguments
                    644:  * 3) daemonize
                    645:  * 4) open syslog
                    646:  * 5) check and write pid file
                    647:  * 6) set startup time stamp
                    648:  * 7) compute presentation URL
                    649:  * 8) set signal handlers */
                    650: static int
                    651: init(int argc, char * * argv, struct runtime_vars * v)
                    652: {
                    653:        int i;
                    654:        int pid;
                    655:        int debug_flag = 0;
                    656:        int openlog_option;
                    657:        struct sigaction sa;
                    658:        /*const char * logfilename = 0;*/
                    659:        const char * presurl = 0;
1.1.1.3 ! misho     660: #ifndef DISABLE_CONFIG_FILE
        !           661:        int options_flag = 0;
1.1       misho     662:        const char * optionsfile = DEFAULT_CONFIG;
1.1.1.3 ! misho     663: #endif /* DISABLE_CONFIG_FILE */
1.1.1.2   misho     664:        struct lan_addr_s * lan_addr;
                    665:        struct lan_addr_s * lan_addr2;
1.1       misho     666: 
                    667:        /* only print usage if -h is used */
                    668:        for(i=1; i<argc; i++)
                    669:        {
                    670:                if(0 == strcmp(argv[i], "-h"))
                    671:                        goto print_usage;
                    672:        }
1.1.1.3 ! misho     673: #ifndef DISABLE_CONFIG_FILE
1.1       misho     674:        /* first check if "-f" option is used */
                    675:        for(i=2; i<argc; i++)
                    676:        {
                    677:                if(0 == strcmp(argv[i-1], "-f"))
                    678:                {
                    679:                        optionsfile = argv[i];
                    680:                        options_flag = 1;
                    681:                        break;
                    682:                }
                    683:        }
1.1.1.3 ! misho     684: #endif /* DISABLE_CONFIG_FILE */
1.1       misho     685: 
                    686:        /* set initial values */
1.1.1.3 ! misho     687:        SETFLAG(ENABLEUPNPMASK);        /* UPnP is enabled by default */
1.1       misho     688: 
1.1.1.2   misho     689:        LIST_INIT(&lan_addrs);
1.1       misho     690:        v->port = -1;
                    691:        v->notify_interval = 30;        /* seconds between SSDP announces */
                    692:        v->clean_ruleset_threshold = 20;
                    693:        v->clean_ruleset_interval = 0;  /* interval between ruleset check. 0=disabled */
1.1.1.3 ! misho     694: #ifndef DISABLE_CONFIG_FILE
1.1       misho     695:        /* read options file first since
                    696:         * command line arguments have final say */
                    697:        if(readoptionsfile(optionsfile) < 0)
                    698:        {
                    699:                /* only error if file exists or using -f */
                    700:                if(access(optionsfile, F_OK) == 0 || options_flag)
                    701:                        fprintf(stderr, "Error reading configuration file %s\n", optionsfile);
                    702:        }
                    703:        else
                    704:        {
1.1.1.3 ! misho     705:                for(i=0; i<(int)num_options; i++)
1.1       misho     706:                {
                    707:                        switch(ary_options[i].id)
                    708:                        {
                    709:                        case UPNPEXT_IFNAME:
                    710:                                ext_if_name = ary_options[i].value;
                    711:                                break;
                    712:                        case UPNPEXT_IP:
                    713:                                use_ext_ip_addr = ary_options[i].value;
                    714:                                break;
                    715:                        case UPNPLISTENING_IP:
1.1.1.2   misho     716:                                lan_addr = (struct lan_addr_s *) malloc(sizeof(struct lan_addr_s));
                    717:                                if (lan_addr == NULL)
1.1       misho     718:                                {
1.1.1.2   misho     719:                                        fprintf(stderr, "malloc(sizeof(struct lan_addr_s)): %m");
                    720:                                        break;
1.1       misho     721:                                }
1.1.1.2   misho     722:                                if(parselanaddr(lan_addr, ary_options[i].value) != 0)
1.1       misho     723:                                {
1.1.1.2   misho     724:                                        fprintf(stderr, "can't parse \"%s\" as valid lan address\n", ary_options[i].value);
                    725:                                        free(lan_addr);
                    726:                                        break;
1.1       misho     727:                                }
1.1.1.2   misho     728:                                LIST_INSERT_HEAD(&lan_addrs, lan_addr, list);
1.1       misho     729:                                break;
                    730:                        case UPNPPORT:
                    731:                                v->port = atoi(ary_options[i].value);
                    732:                                break;
                    733:                        case UPNPBITRATE_UP:
                    734:                                upstream_bitrate = strtoul(ary_options[i].value, 0, 0);
                    735:                                break;
                    736:                        case UPNPBITRATE_DOWN:
                    737:                                downstream_bitrate = strtoul(ary_options[i].value, 0, 0);
                    738:                                break;
                    739:                        case UPNPPRESENTATIONURL:
                    740:                                presurl = ary_options[i].value;
                    741:                                break;
1.1.1.3 ! misho     742:                        case UPNPFRIENDLY_NAME:
        !           743:                                strncpy(friendly_name, ary_options[i].value, FRIENDLY_NAME_MAX_LEN);
        !           744:                                friendly_name[FRIENDLY_NAME_MAX_LEN-1] = '\0';
        !           745:                                break;
1.1       misho     746: #ifdef USE_NETFILTER
                    747:                        case UPNPFORWARDCHAIN:
                    748:                                miniupnpd_forward_chain = ary_options[i].value;
                    749:                                break;
                    750:                        case UPNPNATCHAIN:
                    751:                                miniupnpd_nat_chain = ary_options[i].value;
                    752:                                break;
                    753: #endif
                    754:                        case UPNPNOTIFY_INTERVAL:
                    755:                                v->notify_interval = atoi(ary_options[i].value);
                    756:                                break;
                    757:                        case UPNPSYSTEM_UPTIME:
                    758:                                if(strcmp(ary_options[i].value, "yes") == 0)
                    759:                                        SETFLAG(SYSUPTIMEMASK); /*sysuptime = 1;*/
                    760:                                break;
1.1.1.3 ! misho     761: #if defined(USE_PF) || defined(USE_IPF)
1.1       misho     762:                        case UPNPPACKET_LOG:
                    763:                                if(strcmp(ary_options[i].value, "yes") == 0)
                    764:                                        SETFLAG(LOGPACKETSMASK);        /*logpackets = 1;*/
                    765:                                break;
1.1.1.3 ! misho     766: #endif
1.1       misho     767:                        case UPNPUUID:
                    768:                                strncpy(uuidvalue+5, ary_options[i].value,
                    769:                                        strlen(uuidvalue+5) + 1);
                    770:                                break;
                    771:                        case UPNPSERIAL:
                    772:                                strncpy(serialnumber, ary_options[i].value, SERIALNUMBER_MAX_LEN);
                    773:                                serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0';
1.1.1.3 ! misho     774:                                break;
1.1       misho     775:                        case UPNPMODEL_NUMBER:
                    776:                                strncpy(modelnumber, ary_options[i].value, MODELNUMBER_MAX_LEN);
                    777:                                modelnumber[MODELNUMBER_MAX_LEN-1] = '\0';
                    778:                                break;
                    779:                        case UPNPCLEANTHRESHOLD:
                    780:                                v->clean_ruleset_threshold = atoi(ary_options[i].value);
                    781:                                break;
                    782:                        case UPNPCLEANINTERVAL:
                    783:                                v->clean_ruleset_interval = atoi(ary_options[i].value);
                    784:                                break;
                    785: #ifdef USE_PF
1.1.1.3 ! misho     786:                        case UPNPANCHOR:
        !           787:                                anchor_name = ary_options[i].value;
        !           788:                                break;
1.1       misho     789:                        case UPNPQUEUE:
                    790:                                queue = ary_options[i].value;
                    791:                                break;
                    792:                        case UPNPTAG:
                    793:                                tag = ary_options[i].value;
                    794:                                break;
                    795: #endif
                    796: #ifdef ENABLE_NATPMP
                    797:                        case UPNPENABLENATPMP:
                    798:                                if(strcmp(ary_options[i].value, "yes") == 0)
                    799:                                        SETFLAG(ENABLENATPMPMASK);      /*enablenatpmp = 1;*/
                    800:                                else
                    801:                                        if(atoi(ary_options[i].value))
                    802:                                                SETFLAG(ENABLENATPMPMASK);
                    803:                                        /*enablenatpmp = atoi(ary_options[i].value);*/
                    804:                                break;
                    805: #endif
                    806: #ifdef PF_ENABLE_FILTER_RULES
                    807:                        case UPNPQUICKRULES:
                    808:                                if(strcmp(ary_options[i].value, "no") == 0)
                    809:                                        SETFLAG(PFNOQUICKRULESMASK);
                    810:                                break;
                    811: #endif
                    812:                        case UPNPENABLE:
                    813:                                if(strcmp(ary_options[i].value, "yes") != 0)
                    814:                                        CLEARFLAG(ENABLEUPNPMASK);
                    815:                                break;
                    816:                        case UPNPSECUREMODE:
                    817:                                if(strcmp(ary_options[i].value, "yes") == 0)
                    818:                                        SETFLAG(SECUREMODEMASK);
                    819:                                break;
                    820: #ifdef ENABLE_LEASEFILE
                    821:                        case UPNPLEASEFILE:
                    822:                                lease_file = ary_options[i].value;
                    823:                                break;
                    824: #endif
                    825:                        case UPNPMINISSDPDSOCKET:
                    826:                                minissdpdsocketpath = ary_options[i].value;
                    827:                                break;
                    828:                        default:
                    829:                                fprintf(stderr, "Unknown option in file %s\n",
                    830:                                        optionsfile);
                    831:                        }
                    832:                }
                    833:        }
1.1.1.3 ! misho     834: #endif /* DISABLE_CONFIG_FILE */
1.1       misho     835: 
                    836:        /* command line arguments processing */
                    837:        for(i=1; i<argc; i++)
                    838:        {
                    839:                if(argv[i][0]!='-')
                    840:                {
                    841:                        fprintf(stderr, "Unknown option: %s\n", argv[i]);
                    842:                }
                    843:                else switch(argv[i][1])
                    844:                {
                    845:                case 'o':
                    846:                        if(i+1 < argc)
                    847:                                use_ext_ip_addr = argv[++i];
                    848:                        else
                    849:                                fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
                    850:                        break;
                    851:                case 't':
                    852:                        if(i+1 < argc)
                    853:                                v->notify_interval = atoi(argv[++i]);
                    854:                        else
                    855:                                fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
                    856:                        break;
1.1.1.3 ! misho     857:                case 'r':
        !           858:                        if(i+1 < argc)
        !           859:                                v->clean_ruleset_interval = atoi(argv[++i]);
        !           860:                        else
        !           861:                                fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
        !           862:                        break;
1.1       misho     863:                case 'u':
                    864:                        if(i+1 < argc)
                    865:                                strncpy(uuidvalue+5, argv[++i], strlen(uuidvalue+5) + 1);
                    866:                        else
                    867:                                fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
                    868:                        break;
1.1.1.3 ! misho     869:                case 'z':
        !           870:                        if(i+1 < argc)
        !           871:                                strncpy(friendly_name, argv[++i], FRIENDLY_NAME_MAX_LEN);
        !           872:                        else
        !           873:                                fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
        !           874:                        friendly_name[FRIENDLY_NAME_MAX_LEN-1] = '\0';
        !           875:                        break;
1.1       misho     876:                case 's':
                    877:                        if(i+1 < argc)
                    878:                                strncpy(serialnumber, argv[++i], SERIALNUMBER_MAX_LEN);
                    879:                        else
                    880:                                fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
                    881:                        serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0';
                    882:                        break;
                    883:                case 'm':
                    884:                        if(i+1 < argc)
                    885:                                strncpy(modelnumber, argv[++i], MODELNUMBER_MAX_LEN);
                    886:                        else
                    887:                                fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
                    888:                        modelnumber[MODELNUMBER_MAX_LEN-1] = '\0';
                    889:                        break;
                    890: #ifdef ENABLE_NATPMP
                    891:                case 'N':
                    892:                        /*enablenatpmp = 1;*/
                    893:                        SETFLAG(ENABLENATPMPMASK);
                    894:                        break;
                    895: #endif
                    896:                case 'U':
                    897:                        /*sysuptime = 1;*/
                    898:                        SETFLAG(SYSUPTIMEMASK);
                    899:                        break;
                    900:                /*case 'l':
                    901:                        logfilename = argv[++i];
                    902:                        break;*/
1.1.1.3 ! misho     903: #if defined(USE_PF) || defined(USE_IPF)
1.1       misho     904:                case 'L':
                    905:                        /*logpackets = 1;*/
                    906:                        SETFLAG(LOGPACKETSMASK);
                    907:                        break;
1.1.1.3 ! misho     908: #endif
1.1       misho     909:                case 'S':
                    910:                        SETFLAG(SECUREMODEMASK);
                    911:                        break;
                    912:                case 'i':
                    913:                        if(i+1 < argc)
                    914:                                ext_if_name = argv[++i];
                    915:                        else
                    916:                                fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
                    917:                        break;
                    918: #ifdef USE_PF
                    919:                case 'q':
                    920:                        if(i+1 < argc)
                    921:                                queue = argv[++i];
                    922:                        else
                    923:                                fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
                    924:                        break;
                    925:                case 'T':
                    926:                        if(i+1 < argc)
                    927:                                tag = argv[++i];
                    928:                        else
                    929:                                fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
                    930:                        break;
                    931: #endif
                    932:                case 'p':
                    933:                        if(i+1 < argc)
                    934:                                v->port = atoi(argv[++i]);
                    935:                        else
                    936: #ifdef ENABLE_NFQUEUE
                    937:                case 'Q':
                    938:                        if(i+1<argc)
                    939:                        {
                    940:                                nfqueue = atoi(argv[++i]);
                    941:                        }
                    942:                        else
                    943:                                fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
                    944:                        break;
                    945:                case 'n':
                    946:                        if (i+1 < argc) {
                    947:                                i++;
                    948:                                if(n_nfqix < MAX_LAN_ADDR) {
                    949:                                        nfqix[n_nfqix++] = if_nametoindex(argv[i]);
                    950:                                } else {
                    951:                                        fprintf(stderr,"Too many nfq interfaces. Ignoring %s\n", argv[i]);
                    952:                                }
                    953:                        } else {
                    954:                                fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
                    955:                        }
                    956:                        break;
                    957: #endif
                    958:                                fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
                    959:                        break;
                    960:                case 'P':
                    961:                        if(i+1 < argc)
                    962:                                pidfilename = argv[++i];
                    963:                        else
                    964:                                fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
                    965:                        break;
                    966:                case 'd':
                    967:                        debug_flag = 1;
                    968:                        break;
                    969:                case 'w':
                    970:                        if(i+1 < argc)
                    971:                                presurl = argv[++i];
                    972:                        else
                    973:                                fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
                    974:                        break;
                    975:                case 'B':
                    976:                        if(i+2<argc)
                    977:                        {
                    978:                                downstream_bitrate = strtoul(argv[++i], 0, 0);
                    979:                                upstream_bitrate = strtoul(argv[++i], 0, 0);
                    980:                        }
                    981:                        else
                    982:                                fprintf(stderr, "Option -%c takes two arguments.\n", argv[i][1]);
                    983:                        break;
                    984:                case 'a':
1.1.1.3 ! misho     985: #ifndef MULTIPLE_EXTERNAL_IP
1.1       misho     986:                        if(i+1 < argc)
                    987:                        {
                    988:                                i++;
1.1.1.2   misho     989:                                lan_addr = (struct lan_addr_s *) malloc(sizeof(struct lan_addr_s));
                    990:                                if (lan_addr == NULL)
1.1       misho     991:                                {
1.1.1.2   misho     992:                                        fprintf(stderr, "malloc(sizeof(struct lan_addr_s)): %m");
1.1       misho     993:                                        break;
1.1.1.2   misho     994:                                }
                    995:                                if(parselanaddr(lan_addr, argv[i]) != 0)
1.1       misho     996:                                {
1.1.1.2   misho     997:                                        fprintf(stderr, "can't parse \"%s\" as valid lan address\n", argv[i]);
                    998:                                        free(lan_addr);
                    999:                                        break;
1.1       misho    1000:                                }
1.1.1.2   misho    1001:                                /* check if we already have this address */
                   1002:                                for(lan_addr2 = lan_addrs.lh_first; lan_addr2 != NULL; lan_addr2 = lan_addr2->list.le_next)
1.1       misho    1003:                                {
1.1.1.2   misho    1004:                                        if (0 == strncmp(lan_addr2->str, lan_addr->str, 15))
                   1005:                                                break;
1.1       misho    1006:                                }
1.1.1.2   misho    1007:                                if (lan_addr2 == NULL)
                   1008:                                        LIST_INSERT_HEAD(&lan_addrs, lan_addr, list);
1.1       misho    1009:                        }
                   1010:                        else
                   1011:                                fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
1.1.1.3 ! misho    1012: #else
        !          1013:                        if(i+2 < argc)
        !          1014:                        {
        !          1015:                                char *val=calloc((strlen(argv[i+1]) + strlen(argv[i+2]) + 1), sizeof(char));
        !          1016:                                if (val == NULL)
        !          1017:                                {
        !          1018:                                        fprintf(stderr, "memory allocation error for listen address storage\n");
        !          1019:                                        break;
        !          1020:                                }
        !          1021:                                sprintf(val, "%s %s", argv[i+1], argv[i+2]);
        !          1022: 
        !          1023:                                lan_addr = (struct lan_addr_s *) malloc(sizeof(struct lan_addr_s));
        !          1024:                                if (lan_addr == NULL)
        !          1025:                                {
        !          1026:                                        fprintf(stderr, "malloc(sizeof(struct lan_addr_s)): %m");
        !          1027:                                        free(val);
        !          1028:                                        break;
        !          1029:                                }
        !          1030:                                if(parselanaddr(lan_addr, val) != 0)
        !          1031:                                {
        !          1032:                                        fprintf(stderr, "can't parse \"%s\" as valid lan address\n", val);
        !          1033:                                        free(lan_addr);
        !          1034:                                        free(val);
        !          1035:                                        break;
        !          1036:                                }
        !          1037:                                /* check if we already have this address */
        !          1038:                                for(lan_addr2 = lan_addrs.lh_first; lan_addr2 != NULL; lan_addr2 = lan_addr2->list.le_next)
        !          1039:                                {
        !          1040:                                        if (0 == strncmp(lan_addr2->str, lan_addr->str, 15))
        !          1041:                                                break;
        !          1042:                                }
        !          1043:                                if (lan_addr2 == NULL)
        !          1044:                                        LIST_INSERT_HEAD(&lan_addrs, lan_addr, list);
        !          1045: 
        !          1046:                                free(val);
        !          1047:                                i+=2;
        !          1048:                        }
        !          1049:                        else
        !          1050:                                fprintf(stderr, "Option -%c takes two arguments.\n", argv[i][1]);
        !          1051: #endif
        !          1052:                        break;
        !          1053:                case 'A':
        !          1054:                        if(i+1 < argc) {
        !          1055:                                void * tmp;
        !          1056:                                tmp = realloc(upnppermlist, sizeof(struct upnpperm) * (num_upnpperm+1));
        !          1057:                                if(tmp == NULL) {
        !          1058:                                        fprintf(stderr, "memory allocation error for permission\n");
        !          1059:                                } else {
        !          1060:                                        upnppermlist = tmp;
        !          1061:                                        if(read_permission_line(upnppermlist + num_upnpperm, argv[++i]) >= 0) {
        !          1062:                                                num_upnpperm++;
        !          1063:                                        } else {
        !          1064:                                                fprintf(stderr, "Permission rule parsing error :\n%s\n", argv[i]);
        !          1065:                                        }
        !          1066:                                }
        !          1067:                        } else
        !          1068:                                fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
1.1       misho    1069:                        break;
                   1070:                case 'f':
                   1071:                        i++;    /* discarding, the config file is already read */
                   1072:                        break;
                   1073:                default:
                   1074:                        fprintf(stderr, "Unknown option: %s\n", argv[i]);
                   1075:                }
                   1076:        }
1.1.1.2   misho    1077:        if(!ext_if_name || !lan_addrs.lh_first)
1.1       misho    1078:        {
                   1079:                /* bad configuration */
                   1080:                goto print_usage;
                   1081:        }
                   1082: 
                   1083:        if(debug_flag)
                   1084:        {
                   1085:                pid = getpid();
                   1086:        }
                   1087:        else
                   1088:        {
                   1089: #ifdef USE_DAEMON
                   1090:                if(daemon(0, 0)<0) {
                   1091:                        perror("daemon()");
                   1092:                }
                   1093:                pid = getpid();
                   1094: #else
                   1095:                pid = daemonize();
                   1096: #endif
                   1097:        }
                   1098: 
                   1099:        openlog_option = LOG_PID|LOG_CONS;
                   1100:        if(debug_flag)
                   1101:        {
                   1102:                openlog_option |= LOG_PERROR;   /* also log on stderr */
                   1103:        }
                   1104: 
                   1105:        openlog("miniupnpd", openlog_option, LOG_MINIUPNPD);
                   1106: 
                   1107:        if(!debug_flag)
                   1108:        {
                   1109:                /* speed things up and ignore LOG_INFO and LOG_DEBUG */
                   1110:                setlogmask(LOG_UPTO(LOG_NOTICE));
                   1111:        }
                   1112: 
                   1113:        if(checkforrunning(pidfilename) < 0)
                   1114:        {
                   1115:                syslog(LOG_ERR, "MiniUPnPd is already running. EXITING");
                   1116:                return 1;
1.1.1.3 ! misho    1117:        }
1.1       misho    1118: 
                   1119:        set_startup_time(GETFLAG(SYSUPTIMEMASK));
                   1120: 
                   1121:        /* presentation url */
                   1122:        if(presurl)
                   1123:        {
                   1124:                strncpy(presentationurl, presurl, PRESENTATIONURL_MAX_LEN);
                   1125:                presentationurl[PRESENTATIONURL_MAX_LEN-1] = '\0';
                   1126:        }
                   1127:        else
                   1128:        {
                   1129:                snprintf(presentationurl, PRESENTATIONURL_MAX_LEN,
1.1.1.2   misho    1130:                         "http://%s/", lan_addrs.lh_first->str);
                   1131:                         /*"http://%s:%d/", lan_addrs.lh_first->str, 80);*/
1.1       misho    1132:        }
                   1133: 
                   1134:        /* set signal handler */
                   1135:        memset(&sa, 0, sizeof(struct sigaction));
                   1136:        sa.sa_handler = sigterm;
                   1137: 
1.1.1.3 ! misho    1138:        if(sigaction(SIGTERM, &sa, NULL) < 0)
1.1       misho    1139:        {
                   1140:                syslog(LOG_ERR, "Failed to set %s handler. EXITING", "SIGTERM");
                   1141:                return 1;
                   1142:        }
1.1.1.3 ! misho    1143:        if(sigaction(SIGINT, &sa, NULL) < 0)
1.1       misho    1144:        {
                   1145:                syslog(LOG_ERR, "Failed to set %s handler. EXITING", "SIGINT");
                   1146:                return 1;
                   1147:        }
1.1.1.3 ! misho    1148:        sa.sa_handler = SIG_IGN;
        !          1149:        if(sigaction(SIGPIPE, &sa, NULL) < 0)
        !          1150:        {
1.1       misho    1151:                syslog(LOG_ERR, "Failed to ignore SIGPIPE signals");
                   1152:        }
                   1153:        sa.sa_handler = sigusr1;
1.1.1.3 ! misho    1154:        if(sigaction(SIGUSR1, &sa, NULL) < 0)
1.1       misho    1155:        {
                   1156:                syslog(LOG_NOTICE, "Failed to set %s handler", "SIGUSR1");
                   1157:        }
                   1158: 
                   1159:        if(init_redirect() < 0)
                   1160:        {
                   1161:                syslog(LOG_ERR, "Failed to init redirection engine. EXITING");
                   1162:                return 1;
                   1163:        }
1.1.1.3 ! misho    1164: #ifdef ENABLE_6FC_SERVICE
        !          1165: #ifdef USE_NETFILTER
        !          1166:        init_iptpinhole();
        !          1167: #endif
        !          1168: #endif
1.1       misho    1169: 
1.1.1.3 ! misho    1170:        if(writepidfile(pidfilename, pid) < 0)
        !          1171:                pidfilename = NULL;
1.1       misho    1172: 
                   1173: #ifdef ENABLE_LEASEFILE
                   1174:        /*remove(lease_file);*/
                   1175:        syslog(LOG_INFO, "Reloading rules from lease file");
                   1176:        reload_from_lease_file();
                   1177: #endif
                   1178: 
                   1179:        return 0;
                   1180: print_usage:
                   1181:        fprintf(stderr, "Usage:\n\t"
1.1.1.3 ! misho    1182:                "%s "
        !          1183: #ifndef DISABLE_CONFIG_FILE
        !          1184:                        "[-f config_file] "
        !          1185: #endif
        !          1186:                        "[-i ext_ifname] [-o ext_ip]\n"
        !          1187: #ifndef MULTIPLE_EXTERNAL_IP
        !          1188:                        "\t\t[-a listening_ip]"
1.1       misho    1189: #else
1.1.1.3 ! misho    1190:                        "\t\t[-a listening_ip ext_ip]"
        !          1191: #endif
        !          1192:                        " [-p port] [-d]"
        !          1193: #if defined(USE_PF) || defined(USE_IPF)
        !          1194:                        " [-L]"
        !          1195: #endif
        !          1196:                        " [-U] [-S]"
        !          1197: #ifdef ENABLE_NATPMP
        !          1198:                        " [-N]"
1.1       misho    1199: #endif
1.1.1.3 ! misho    1200:                        "\n"
1.1       misho    1201:                        /*"[-l logfile] " not functionnal */
                   1202:                        "\t\t[-u uuid] [-s serial] [-m model_number] \n"
1.1.1.3 ! misho    1203:                        "\t\t[-t notify_interval] [-P pid_filename] [-z fiendly_name]\n"
        !          1204:                        "\t\t[-B down up] [-w url] [-r clean_ruleset_interval]\n"
1.1       misho    1205: #ifdef USE_PF
                   1206:                         "\t\t[-q queue] [-T tag]\n"
                   1207: #endif
                   1208: #ifdef ENABLE_NFQUEUE
                   1209:                         "\t\t[-Q queue] [-n name]\n"
                   1210: #endif
1.1.1.3 ! misho    1211:                        "\t\t[-A \"permission rule\"]\n"
1.1       misho    1212:                "\nNotes:\n\tThere can be one or several listening_ips.\n"
                   1213:                "\tNotify interval is in seconds. Default is 30 seconds.\n"
                   1214:                        "\tDefault pid file is '%s'.\n"
                   1215:                        "\tDefault config file is '%s'.\n"
                   1216:                        "\tWith -d miniupnpd will run as a standard program.\n"
1.1.1.3 ! misho    1217: #if defined(USE_PF) || defined(USE_IPF)
1.1       misho    1218:                        "\t-L sets packet log in pf and ipf on.\n"
1.1.1.3 ! misho    1219: #endif
1.1       misho    1220:                        "\t-S sets \"secure\" mode : clients can only add mappings to their own ip\n"
                   1221:                        "\t-U causes miniupnpd to report system uptime instead "
                   1222:                        "of daemon uptime.\n"
                   1223: #ifdef ENABLE_NATPMP
1.1.1.3 ! misho    1224:                        "\t-N enable NAT-PMP functionality.\n"
1.1       misho    1225: #endif
                   1226:                        "\t-B sets bitrates reported by daemon in bits per second.\n"
                   1227:                        "\t-w sets the presentation url. Default is http address on port 80\n"
                   1228: #ifdef USE_PF
                   1229:                        "\t-q sets the ALTQ queue in pf.\n"
                   1230:                        "\t-T sets the tag name in pf.\n"
                   1231: #endif
                   1232: #ifdef ENABLE_NFQUEUE
1.1.1.3 ! misho    1233:                        "\t-Q sets the queue number that is used by NFQUEUE.\n"
        !          1234:                        "\t-n sets the name of the interface(s) that packets will arrive on.\n"
1.1       misho    1235: #endif
1.1.1.3 ! misho    1236:                        "\t-A use following syntax for permission rules :\n"
        !          1237:                        "\t  (allow|deny) (external port range) ip/mask (internal port range)\n"
        !          1238:                        "\texamples :\n"
        !          1239:                        "\t  \"allow 1024-65535 192.168.1.0/24 1024-65535\"\n"
        !          1240:                        "\t  \"deny 0-65535 0.0.0.0/0 0-65535\"\n"
1.1       misho    1241:                        "\t-h prints this help and quits.\n"
                   1242:                "", argv[0], pidfilename, DEFAULT_CONFIG);
                   1243:        return 1;
                   1244: }
                   1245: 
                   1246: /* === main === */
                   1247: /* process HTTP or SSDP requests */
                   1248: int
                   1249: main(int argc, char * * argv)
                   1250: {
                   1251:        int i;
1.1.1.2   misho    1252:        int shttpl = -1;        /* socket for HTTP */
                   1253:        int sudp = -1;          /* IP v4 socket for receiving SSDP */
                   1254: #ifdef ENABLE_IPV6
                   1255:        int sudpv6 = -1;        /* IP v6 socket for receiving SSDP */
                   1256: #endif
1.1       misho    1257: #ifdef ENABLE_NATPMP
1.1.1.3 ! misho    1258:        int * snatpmp = NULL;
1.1.1.2   misho    1259: #endif
1.1       misho    1260: #ifdef ENABLE_NFQUEUE
                   1261:        int nfqh = -1;
                   1262: #endif
1.1.1.2   misho    1263: #ifdef USE_IFACEWATCHER
                   1264:        int sifacewatcher = -1;
1.1       misho    1265: #endif
1.1.1.2   misho    1266: 
1.1.1.3 ! misho    1267:        int * snotify = NULL;
1.1.1.2   misho    1268:        int addr_count;
1.1       misho    1269:        LIST_HEAD(httplisthead, upnphttp) upnphttphead;
                   1270:        struct upnphttp * e = 0;
                   1271:        struct upnphttp * next;
                   1272:        fd_set readset; /* for select() */
                   1273:        fd_set writeset;
                   1274:        struct timeval timeout, timeofday, lasttimeofday = {0, 0};
                   1275:        int max_fd = -1;
                   1276: #ifdef USE_MINIUPNPDCTL
                   1277:        int sctl = -1;
                   1278:        LIST_HEAD(ctlstructhead, ctlelem) ctllisthead;
                   1279:        struct ctlelem * ectl;
                   1280:        struct ctlelem * ectlnext;
                   1281: #endif
                   1282:        struct runtime_vars v;
                   1283:        /* variables used for the unused-rule cleanup process */
                   1284:        struct rule_state * rule_list = 0;
                   1285:        struct timeval checktime = {0, 0};
1.1.1.2   misho    1286:        struct lan_addr_s * lan_addr;
1.1.1.3 ! misho    1287: #ifdef ENABLE_6FC_SERVICE
        !          1288:        unsigned int next_pinhole_ts;
        !          1289: #endif
1.1       misho    1290: 
1.1.1.2   misho    1291:        if(init(argc, argv, &v) != 0)
                   1292:                return 1;
                   1293:        /* count lan addrs */
                   1294:        addr_count = 0;
                   1295:        for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next)
                   1296:                addr_count++;
1.1.1.3 ! misho    1297:        if(addr_count > 0) {
        !          1298: #ifndef ENABLE_IPV6
        !          1299:                snotify = calloc(addr_count, sizeof(int));
        !          1300: #else
        !          1301:                /* one for IPv4, one for IPv6 */
        !          1302:                snotify = calloc(addr_count * 2, sizeof(int));
        !          1303: #endif
        !          1304:        }
1.1       misho    1305: #ifdef ENABLE_NATPMP
1.1.1.3 ! misho    1306:        if(addr_count > 0) {
        !          1307:                snatpmp = malloc(addr_count * sizeof(int));
        !          1308:                for(i = 0; i < addr_count; i++)
        !          1309:                        snatpmp[i] = -1;
        !          1310:        }
1.1       misho    1311: #endif
                   1312: 
                   1313:        LIST_INIT(&upnphttphead);
                   1314: #ifdef USE_MINIUPNPDCTL
                   1315:        LIST_INIT(&ctllisthead);
                   1316: #endif
                   1317: 
                   1318:        if(
                   1319: #ifdef ENABLE_NATPMP
                   1320:         !GETFLAG(ENABLENATPMPMASK) &&
                   1321: #endif
                   1322:         !GETFLAG(ENABLEUPNPMASK) ) {
                   1323:                syslog(LOG_ERR, "Why did you run me anyway?");
                   1324:                return 0;
                   1325:        }
                   1326: 
1.1.1.3 ! misho    1327:        syslog(LOG_INFO, "Starting%s%swith external interface %s",
        !          1328: #ifdef ENABLE_NATPMP
        !          1329:               GETFLAG(ENABLENATPMPMASK) ? " NAT-PMP " : " ",
        !          1330: #else
        !          1331:               " ",
        !          1332: #endif
        !          1333:               GETFLAG(ENABLEUPNPMASK) ? "UPnP-IGD " : "",
        !          1334:               ext_if_name);
        !          1335: 
1.1       misho    1336:        if(GETFLAG(ENABLEUPNPMASK))
                   1337:        {
                   1338: 
                   1339:                /* open socket for HTTP connections. Listen on the 1st LAN address */
                   1340:                shttpl = OpenAndConfHTTPSocket((v.port > 0) ? v.port : 0);
                   1341:                if(shttpl < 0)
                   1342:                {
                   1343:                        syslog(LOG_ERR, "Failed to open socket for HTTP. EXITING");
                   1344:                        return 1;
                   1345:                }
                   1346:                if(v.port <= 0) {
                   1347:                        struct sockaddr_in sockinfo;
                   1348:                        socklen_t len = sizeof(struct sockaddr_in);
                   1349:                        if (getsockname(shttpl, (struct sockaddr *)&sockinfo, &len) < 0) {
                   1350:                                syslog(LOG_ERR, "getsockname(): %m");
                   1351:                                return 1;
                   1352:                        }
                   1353:                        v.port = ntohs(sockinfo.sin_port);
                   1354:                }
                   1355:                syslog(LOG_NOTICE, "HTTP listening on port %d", v.port);
1.1.1.2   misho    1356: #ifdef ENABLE_IPV6
                   1357:                if(find_ipv6_addr(NULL, ipv6_addr_for_http_with_brackets, sizeof(ipv6_addr_for_http_with_brackets)) > 0) {
                   1358:                        syslog(LOG_NOTICE, "HTTP IPv6 address given to control points : %s",
                   1359:                               ipv6_addr_for_http_with_brackets);
                   1360:                } else {
                   1361:                        memcpy(ipv6_addr_for_http_with_brackets, "[::1]", 6);
                   1362:                        syslog(LOG_WARNING, "no HTTP IPv6 address");
                   1363:                }
                   1364: #endif
1.1       misho    1365: 
                   1366:                /* open socket for SSDP connections */
1.1.1.2   misho    1367:                sudp = OpenAndConfSSDPReceiveSocket(0);
1.1       misho    1368:                if(sudp < 0)
                   1369:                {
1.1.1.3 ! misho    1370:                        syslog(LOG_NOTICE, "Failed to open socket for receiving SSDP. Trying to use MiniSSDPd");
1.1.1.2   misho    1371:                        if(SubmitServicesToMiniSSDPD(lan_addrs.lh_first->str, v.port) < 0) {
1.1       misho    1372:                                syslog(LOG_ERR, "Failed to connect to MiniSSDPd. EXITING");
                   1373:                                return 1;
                   1374:                        }
                   1375:                }
1.1.1.2   misho    1376: #ifdef ENABLE_IPV6
                   1377:                sudpv6 = OpenAndConfSSDPReceiveSocket(1);
                   1378:                if(sudpv6 < 0)
                   1379:                {
1.1.1.3 ! misho    1380:                        syslog(LOG_WARNING, "Failed to open socket for receiving SSDP (IP v6).");
1.1.1.2   misho    1381:                }
                   1382: #endif
1.1       misho    1383: 
                   1384:                /* open socket for sending notifications */
                   1385:                if(OpenAndConfSSDPNotifySockets(snotify) < 0)
                   1386:                {
                   1387:                        syslog(LOG_ERR, "Failed to open sockets for sending SSDP notify "
                   1388:                                "messages. EXITING");
                   1389:                        return 1;
                   1390:                }
1.1.1.2   misho    1391: 
                   1392: #ifdef USE_IFACEWATCHER
                   1393:                /* open socket for kernel notifications about new network interfaces */
                   1394:                if (sudp >= 0)
                   1395:                {
                   1396:                        sifacewatcher = OpenAndConfInterfaceWatchSocket();
                   1397:                        if (sifacewatcher < 0)
                   1398:                        {
                   1399:                                syslog(LOG_ERR, "Failed to open socket for receiving network interface notifications");
                   1400:                        }
                   1401:                }
                   1402: #endif
1.1       misho    1403:        }
                   1404: 
                   1405: #ifdef ENABLE_NATPMP
                   1406:        /* open socket for NAT PMP traffic */
                   1407:        if(GETFLAG(ENABLENATPMPMASK))
                   1408:        {
                   1409:                if(OpenAndConfNATPMPSockets(snatpmp) < 0)
                   1410:                {
                   1411:                        syslog(LOG_ERR, "Failed to open sockets for NAT PMP.");
                   1412:                } else {
                   1413:                        syslog(LOG_NOTICE, "Listening for NAT-PMP traffic on port %u",
                   1414:                               NATPMP_PORT);
                   1415:                }
1.1.1.2   misho    1416: #if 0
1.1       misho    1417:                ScanNATPMPforExpiration();
1.1.1.2   misho    1418: #endif
1.1       misho    1419:        }
                   1420: #endif
                   1421: 
                   1422:        /* for miniupnpdctl */
                   1423: #ifdef USE_MINIUPNPDCTL
                   1424:        sctl = OpenAndConfCtlUnixSocket("/var/run/miniupnpd.ctl");
                   1425: #endif
                   1426: 
                   1427: #ifdef ENABLE_NFQUEUE
                   1428:        if ( nfqueue != -1 && n_nfqix > 0) {
                   1429:                nfqh = OpenAndConfNFqueue();
                   1430:                if(nfqh < 0) {
                   1431:                        syslog(LOG_ERR, "Failed to open fd for NFQUEUE.");
                   1432:                        return 1;
                   1433:                } else {
                   1434:                        syslog(LOG_NOTICE, "Opened NFQUEUE %d",nfqueue);
                   1435:                }
                   1436:        }
                   1437: #endif
1.1.1.3 ! misho    1438: 
1.1       misho    1439:        /* main loop */
                   1440:        while(!quitting)
                   1441:        {
                   1442:                /* Correct startup_time if it was set with a RTC close to 0 */
                   1443:                if((startup_time<60*60*24) && (time(NULL)>60*60*24))
                   1444:                {
                   1445:                        set_startup_time(GETFLAG(SYSUPTIMEMASK));
1.1.1.3 ! misho    1446:                }
1.1.1.2   misho    1447:                /* send public address change notifications if needed */
                   1448:                if(should_send_public_address_change_notif)
                   1449:                {
                   1450:                        syslog(LOG_DEBUG, "should send external iface address change notification(s)");
                   1451: #ifdef ENABLE_NATPMP
                   1452:                        if(GETFLAG(ENABLENATPMPMASK))
                   1453:                                SendNATPMPPublicAddressChangeNotification(snatpmp, addr_count);
                   1454: #endif
                   1455: #ifdef ENABLE_EVENTS
                   1456:                        if(GETFLAG(ENABLEUPNPMASK))
                   1457:                        {
                   1458:                                upnp_event_var_change_notify(EWanIPC);
                   1459:                        }
                   1460: #endif
                   1461:                        should_send_public_address_change_notif = 0;
                   1462:                }
1.1       misho    1463:                /* Check if we need to send SSDP NOTIFY messages and do it if
                   1464:                 * needed */
                   1465:                if(gettimeofday(&timeofday, 0) < 0)
                   1466:                {
                   1467:                        syslog(LOG_ERR, "gettimeofday(): %m");
                   1468:                        timeout.tv_sec = v.notify_interval;
                   1469:                        timeout.tv_usec = 0;
                   1470:                }
                   1471:                else
                   1472:                {
                   1473:                        /* the comparaison is not very precise but who cares ? */
                   1474:                        if(timeofday.tv_sec >= (lasttimeofday.tv_sec + v.notify_interval))
                   1475:                        {
                   1476:                                if (GETFLAG(ENABLEUPNPMASK))
                   1477:                                        SendSSDPNotifies2(snotify,
                   1478:                                                  (unsigned short)v.port,
                   1479:                                                  v.notify_interval << 1);
                   1480:                                memcpy(&lasttimeofday, &timeofday, sizeof(struct timeval));
                   1481:                                timeout.tv_sec = v.notify_interval;
                   1482:                                timeout.tv_usec = 0;
                   1483:                        }
                   1484:                        else
                   1485:                        {
                   1486:                                timeout.tv_sec = lasttimeofday.tv_sec + v.notify_interval
                   1487:                                                 - timeofday.tv_sec;
                   1488:                                if(timeofday.tv_usec > lasttimeofday.tv_usec)
                   1489:                                {
                   1490:                                        timeout.tv_usec = 1000000 + lasttimeofday.tv_usec
                   1491:                                                          - timeofday.tv_usec;
                   1492:                                        timeout.tv_sec--;
                   1493:                                }
                   1494:                                else
                   1495:                                {
                   1496:                                        timeout.tv_usec = lasttimeofday.tv_usec - timeofday.tv_usec;
                   1497:                                }
                   1498:                        }
                   1499:                }
                   1500:                /* remove unused rules */
                   1501:                if( v.clean_ruleset_interval
                   1502:                  && (timeofday.tv_sec >= checktime.tv_sec + v.clean_ruleset_interval))
                   1503:                {
                   1504:                        if(rule_list)
                   1505:                        {
                   1506:                                remove_unused_rules(rule_list);
                   1507:                                rule_list = NULL;
                   1508:                        }
                   1509:                        else
                   1510:                        {
                   1511:                                rule_list = get_upnp_rules_state_list(v.clean_ruleset_threshold);
                   1512:                        }
                   1513:                        memcpy(&checktime, &timeofday, sizeof(struct timeval));
                   1514:                }
1.1.1.2   misho    1515:                /* Remove expired port mappings, based on UPnP IGD LeaseDuration
                   1516:                 * or NAT-PMP lifetime) */
                   1517:                if(nextruletoclean_timestamp
1.1.1.3 ! misho    1518:                  && ((unsigned int)timeofday.tv_sec >= nextruletoclean_timestamp))
1.1.1.2   misho    1519:                {
                   1520:                        syslog(LOG_DEBUG, "cleaning expired Port Mappings");
                   1521:                        get_upnp_rules_state_list(0);
                   1522:                }
                   1523:                if(nextruletoclean_timestamp
1.1.1.3 ! misho    1524:                  && ((unsigned int)timeout.tv_sec >= (nextruletoclean_timestamp - timeofday.tv_sec)))
1.1.1.2   misho    1525:                {
                   1526:                        timeout.tv_sec = nextruletoclean_timestamp - timeofday.tv_sec;
                   1527:                        timeout.tv_usec = 0;
                   1528:                        syslog(LOG_DEBUG, "setting timeout to %u sec",
                   1529:                               (unsigned)timeout.tv_sec);
                   1530:                }
1.1       misho    1531: #ifdef ENABLE_NATPMP
1.1.1.2   misho    1532: #if 0
1.1       misho    1533:                /* Remove expired NAT-PMP mappings */
1.1.1.2   misho    1534:                while(nextnatpmptoclean_timestamp
                   1535:                     && (timeofday.tv_sec >= nextnatpmptoclean_timestamp + startup_time))
1.1       misho    1536:                {
                   1537:                        /*syslog(LOG_DEBUG, "cleaning expired NAT-PMP mappings");*/
                   1538:                        if(CleanExpiredNATPMP() < 0) {
                   1539:                                syslog(LOG_ERR, "CleanExpiredNATPMP() failed");
                   1540:                                break;
                   1541:                        }
                   1542:                }
1.1.1.2   misho    1543:                if(nextnatpmptoclean_timestamp
                   1544:                  && timeout.tv_sec >= (nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec))
1.1       misho    1545:                {
1.1.1.2   misho    1546:                        /*syslog(LOG_DEBUG, "setting timeout to %d sec",
                   1547:                               nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec);*/
1.1       misho    1548:                        timeout.tv_sec = nextnatpmptoclean_timestamp + startup_time - timeofday.tv_sec;
                   1549:                        timeout.tv_usec = 0;
                   1550:                }
                   1551: #endif
1.1.1.2   misho    1552: #endif
1.1.1.3 ! misho    1553: #ifdef ENABLE_6FC_SERVICE
        !          1554:                /* Clean up expired IPv6 PinHoles */
        !          1555:                next_pinhole_ts = 0;
        !          1556:                upnp_clean_expired_pinholes(&next_pinhole_ts);
        !          1557:                if(next_pinhole_ts &&
        !          1558:                   timeout.tv_sec >= (int)(next_pinhole_ts - timeofday.tv_sec)) {
        !          1559:                        timeout.tv_sec = next_pinhole_ts - timeofday.tv_sec;
        !          1560:                        timeout.tv_usec = 0;
        !          1561:                }
        !          1562: #endif
1.1       misho    1563: 
                   1564:                /* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */
                   1565:                FD_ZERO(&readset);
1.1.1.3 ! misho    1566:                FD_ZERO(&writeset);
1.1       misho    1567: 
1.1.1.3 ! misho    1568:                if (sudp >= 0)
1.1       misho    1569:                {
                   1570:                        FD_SET(sudp, &readset);
                   1571:                        max_fd = MAX( max_fd, sudp);
1.1.1.2   misho    1572: #ifdef USE_IFACEWATCHER
                   1573:                        if (sifacewatcher >= 0)
                   1574:                        {
                   1575:                                FD_SET(sifacewatcher, &readset);
                   1576:                                max_fd = MAX(max_fd, sifacewatcher);
                   1577:                        }
                   1578: #endif
1.1       misho    1579:                }
1.1.1.3 ! misho    1580:                if (shttpl >= 0)
1.1       misho    1581:                {
                   1582:                        FD_SET(shttpl, &readset);
                   1583:                        max_fd = MAX( max_fd, shttpl);
                   1584:                }
1.1.1.2   misho    1585: #ifdef ENABLE_IPV6
                   1586:                if (sudpv6 >= 0)
                   1587:                {
                   1588:                        FD_SET(sudpv6, &readset);
                   1589:                        max_fd = MAX( max_fd, sudpv6);
                   1590:                }
                   1591: #endif
                   1592: 
                   1593: #ifdef ENABLE_NFQUEUE
1.1.1.3 ! misho    1594:                if (nfqh >= 0)
1.1.1.2   misho    1595:                {
                   1596:                        FD_SET(nfqh, &readset);
                   1597:                        max_fd = MAX( max_fd, nfqh);
                   1598:                }
                   1599: #endif
1.1       misho    1600: 
                   1601:                i = 0;  /* active HTTP connections count */
                   1602:                for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next)
                   1603:                {
1.1.1.3 ! misho    1604:                        if(e->socket >= 0)
1.1       misho    1605:                        {
1.1.1.3 ! misho    1606:                                if(e->state <= EWaitingForHttpContent)
        !          1607:                                        FD_SET(e->socket, &readset);
        !          1608:                                else if(e->state == ESendingAndClosing)
        !          1609:                                        FD_SET(e->socket, &writeset);
        !          1610:                                else
        !          1611:                                        continue;
        !          1612:                                max_fd = MAX(max_fd, e->socket);
1.1       misho    1613:                                i++;
                   1614:                        }
                   1615:                }
                   1616:                /* for debug */
                   1617: #ifdef DEBUG
                   1618:                if(i > 1)
                   1619:                {
                   1620:                        syslog(LOG_DEBUG, "%d active incoming HTTP connections", i);
                   1621:                }
                   1622: #endif
                   1623: #ifdef ENABLE_NATPMP
1.1.1.2   misho    1624:                for(i=0; i<addr_count; i++) {
1.1       misho    1625:                        if(snatpmp[i] >= 0) {
                   1626:                                FD_SET(snatpmp[i], &readset);
                   1627:                                max_fd = MAX( max_fd, snatpmp[i]);
                   1628:                        }
                   1629:                }
                   1630: #endif
                   1631: #ifdef USE_MINIUPNPDCTL
                   1632:                if(sctl >= 0) {
                   1633:                        FD_SET(sctl, &readset);
                   1634:                        max_fd = MAX( max_fd, sctl);
                   1635:                }
1.1.1.3 ! misho    1636: 
1.1       misho    1637:                for(ectl = ctllisthead.lh_first; ectl; ectl = ectl->entries.le_next)
                   1638:                {
                   1639:                        if(ectl->socket >= 0) {
                   1640:                                FD_SET(ectl->socket, &readset);
                   1641:                                max_fd = MAX( max_fd, ectl->socket);
                   1642:                        }
                   1643:                }
                   1644: #endif
                   1645: 
                   1646: #ifdef ENABLE_EVENTS
                   1647:                upnpevents_selectfds(&readset, &writeset, &max_fd);
                   1648: #endif
                   1649: 
                   1650:                if(select(max_fd+1, &readset, &writeset, 0, &timeout) < 0)
                   1651:                {
                   1652:                        if(quitting) goto shutdown;
                   1653:                        if(errno == EINTR) continue; /* interrupted by a signal, start again */
                   1654:                        syslog(LOG_ERR, "select(all): %m");
                   1655:                        syslog(LOG_ERR, "Failed to select open sockets. EXITING");
                   1656:                        return 1;       /* very serious cause of error */
                   1657:                }
                   1658: #ifdef USE_MINIUPNPDCTL
                   1659:                for(ectl = ctllisthead.lh_first; ectl;)
                   1660:                {
                   1661:                        ectlnext =  ectl->entries.le_next;
                   1662:                        if((ectl->socket >= 0) && FD_ISSET(ectl->socket, &readset))
                   1663:                        {
                   1664:                                char buf[256];
                   1665:                                int l;
                   1666:                                l = read(ectl->socket, buf, sizeof(buf));
                   1667:                                if(l > 0)
                   1668:                                {
                   1669:                                        /*write(ectl->socket, buf, l);*/
                   1670:                                        write_command_line(ectl->socket, argc, argv);
1.1.1.3 ! misho    1671: #ifndef DISABLE_CONFIG_FILE
1.1       misho    1672:                                        write_option_list(ectl->socket);
1.1.1.3 ! misho    1673: #endif
1.1       misho    1674:                                        write_permlist(ectl->socket, upnppermlist, num_upnpperm);
                   1675:                                        write_upnphttp_details(ectl->socket, upnphttphead.lh_first);
                   1676:                                        write_ctlsockets_list(ectl->socket, ctllisthead.lh_first);
                   1677:                                        write_ruleset_details(ectl->socket);
                   1678: #ifdef ENABLE_EVENTS
                   1679:                                        write_events_details(ectl->socket);
                   1680: #endif
                   1681:                                        /* close the socket */
                   1682:                                        close(ectl->socket);
                   1683:                                        ectl->socket = -1;
                   1684:                                }
                   1685:                                else
                   1686:                                {
                   1687:                                        close(ectl->socket);
                   1688:                                        ectl->socket = -1;
                   1689:                                }
                   1690:                        }
                   1691:                        if(ectl->socket < 0)
                   1692:                        {
                   1693:                                LIST_REMOVE(ectl, entries);
                   1694:                                free(ectl);
                   1695:                        }
                   1696:                        ectl = ectlnext;
                   1697:                }
                   1698:                if((sctl >= 0) && FD_ISSET(sctl, &readset))
                   1699:                {
                   1700:                        int s;
                   1701:                        struct sockaddr_un clientname;
                   1702:                        struct ctlelem * tmp;
                   1703:                        socklen_t clientnamelen = sizeof(struct sockaddr_un);
1.1.1.3 ! misho    1704:                        /*syslog(LOG_DEBUG, "sctl!");*/
1.1       misho    1705:                        s = accept(sctl, (struct sockaddr *)&clientname,
                   1706:                                   &clientnamelen);
                   1707:                        syslog(LOG_DEBUG, "sctl! : '%s'", clientname.sun_path);
                   1708:                        tmp = malloc(sizeof(struct ctlelem));
1.1.1.3 ! misho    1709:                        if (tmp == NULL)
        !          1710:                        {
        !          1711:                                syslog(LOG_ERR, "Unable to allocate memory for ctlelem in main()");
        !          1712:                                close(s);
        !          1713:                        }
        !          1714:                        else
        !          1715:                        {
        !          1716:                                tmp->socket = s;
        !          1717:                                LIST_INSERT_HEAD(&ctllisthead, tmp, entries);
        !          1718:                        }
1.1       misho    1719:                }
                   1720: #endif
                   1721: #ifdef ENABLE_EVENTS
                   1722:                upnpevents_processfds(&readset, &writeset);
                   1723: #endif
                   1724: #ifdef ENABLE_NATPMP
                   1725:                /* process NAT-PMP packets */
1.1.1.2   misho    1726:                for(i=0; i<addr_count; i++)
1.1       misho    1727:                {
                   1728:                        if((snatpmp[i] >= 0) && FD_ISSET(snatpmp[i], &readset))
                   1729:                        {
                   1730:                                ProcessIncomingNATPMPPacket(snatpmp[i]);
                   1731:                        }
                   1732:                }
                   1733: #endif
                   1734:                /* process SSDP packets */
                   1735:                if(sudp >= 0 && FD_ISSET(sudp, &readset))
                   1736:                {
                   1737:                        /*syslog(LOG_INFO, "Received UDP Packet");*/
                   1738:                        ProcessSSDPRequest(sudp, (unsigned short)v.port);
                   1739:                }
1.1.1.2   misho    1740: #ifdef ENABLE_IPV6
                   1741:                if(sudpv6 >= 0 && FD_ISSET(sudpv6, &readset))
                   1742:                {
                   1743:                        syslog(LOG_INFO, "Received UDP Packet (IPv6)");
                   1744:                        ProcessSSDPRequest(sudpv6, (unsigned short)v.port);
                   1745:                }
                   1746: #endif
                   1747: #ifdef USE_IFACEWATCHER
                   1748:                /* process kernel notifications */
                   1749:                if (sifacewatcher >= 0 && FD_ISSET(sifacewatcher, &readset))
                   1750:                        ProcessInterfaceWatchNotify(sifacewatcher);
                   1751: #endif
                   1752: 
1.1       misho    1753:                /* process active HTTP connections */
                   1754:                /* LIST_FOREACH macro is not available under linux */
                   1755:                for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next)
                   1756:                {
1.1.1.3 ! misho    1757:                        if(e->socket >= 0)
1.1       misho    1758:                        {
1.1.1.3 ! misho    1759:                                if(FD_ISSET(e->socket, &readset) ||
        !          1760:                                   FD_ISSET(e->socket, &writeset))
        !          1761:                                {
        !          1762:                                        Process_upnphttp(e);
        !          1763:                                }
1.1       misho    1764:                        }
                   1765:                }
                   1766:                /* process incoming HTTP connections */
                   1767:                if(shttpl >= 0 && FD_ISSET(shttpl, &readset))
                   1768:                {
                   1769:                        int shttp;
                   1770:                        socklen_t clientnamelen;
1.1.1.2   misho    1771: #ifdef ENABLE_IPV6
                   1772:                        struct sockaddr_storage clientname;
                   1773:                        clientnamelen = sizeof(struct sockaddr_storage);
                   1774: #else
1.1       misho    1775:                        struct sockaddr_in clientname;
                   1776:                        clientnamelen = sizeof(struct sockaddr_in);
1.1.1.2   misho    1777: #endif
1.1       misho    1778:                        shttp = accept(shttpl, (struct sockaddr *)&clientname, &clientnamelen);
                   1779:                        if(shttp<0)
                   1780:                        {
1.1.1.3 ! misho    1781:                                /* ignore EAGAIN, EWOULDBLOCK, EINTR, we just try again later */
        !          1782:                                if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
        !          1783:                                        syslog(LOG_ERR, "accept(http): %m");
1.1       misho    1784:                        }
                   1785:                        else
                   1786:                        {
                   1787:                                struct upnphttp * tmp = 0;
1.1.1.2   misho    1788:                                char addr_str[64];
                   1789: 
                   1790:                                sockaddr_to_string((struct sockaddr *)&clientname, addr_str, sizeof(addr_str));
                   1791:                                syslog(LOG_INFO, "HTTP connection from %s", addr_str);
1.1.1.3 ! misho    1792:                                if(get_lan_for_peer((struct sockaddr *)&clientname) == NULL)
1.1       misho    1793:                                {
1.1.1.3 ! misho    1794:                                        /* The peer is not a LAN ! */
        !          1795:                                        syslog(LOG_WARNING,
        !          1796:                                               "HTTP peer %s is not from a LAN, closing the connection",
        !          1797:                                               addr_str);
        !          1798:                                        close(shttp);
        !          1799:                                }
        !          1800:                                else
        !          1801:                                {
        !          1802:                                        /* Create a new upnphttp object and add it to
        !          1803:                                         * the active upnphttp object list */
        !          1804:                                        tmp = New_upnphttp(shttp);
        !          1805:                                        if(tmp)
1.1.1.2   misho    1806:                                        {
1.1.1.3 ! misho    1807: #ifdef ENABLE_IPV6
        !          1808:                                                if(clientname.ss_family == AF_INET)
1.1.1.2   misho    1809:                                                {
1.1.1.3 ! misho    1810:                                                        tmp->clientaddr = ((struct sockaddr_in *)&clientname)->sin_addr;
1.1.1.2   misho    1811:                                                }
1.1.1.3 ! misho    1812:                                                else if(clientname.ss_family == AF_INET6)
1.1.1.2   misho    1813:                                                {
1.1.1.3 ! misho    1814:                                                        struct sockaddr_in6 * addr = (struct sockaddr_in6 *)&clientname;
        !          1815:                                                        if(IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr))
        !          1816:                                                        {
        !          1817:                                                                memcpy(&tmp->clientaddr,
        !          1818:                                                                       &addr->sin6_addr.s6_addr[12],
        !          1819:                                                                       4);
        !          1820:                                                        }
        !          1821:                                                        else
        !          1822:                                                        {
        !          1823:                                                                tmp->ipv6 = 1;
        !          1824:                                                                memcpy(&tmp->clientaddr_v6,
        !          1825:                                                                       &addr->sin6_addr,
        !          1826:                                                                       sizeof(struct in6_addr));
        !          1827:                                                        }
1.1.1.2   misho    1828:                                                }
                   1829: #else
1.1.1.3 ! misho    1830:                                                tmp->clientaddr = clientname.sin_addr;
1.1.1.2   misho    1831: #endif
1.1.1.3 ! misho    1832:                                                LIST_INSERT_HEAD(&upnphttphead, tmp, entries);
        !          1833:                                        }
        !          1834:                                        else
        !          1835:                                        {
        !          1836:                                                syslog(LOG_ERR, "New_upnphttp() failed");
        !          1837:                                                close(shttp);
        !          1838:                                        }
1.1       misho    1839:                                }
                   1840:                        }
                   1841:                }
1.1.1.2   misho    1842: #ifdef ENABLE_NFQUEUE
                   1843:                /* process NFQ packets */
                   1844:                if(nfqh >= 0 && FD_ISSET(nfqh, &readset))
                   1845:                {
                   1846:                        /* syslog(LOG_INFO, "Received NFQUEUE Packet");*/
                   1847:                        ProcessNFQUEUE(nfqh);
                   1848:                }
                   1849: #endif
1.1       misho    1850:                /* delete finished HTTP connections */
                   1851:                for(e = upnphttphead.lh_first; e != NULL; )
                   1852:                {
                   1853:                        next = e->entries.le_next;
1.1.1.3 ! misho    1854:                        if(e->state >= EToDelete)
1.1       misho    1855:                        {
                   1856:                                LIST_REMOVE(e, entries);
                   1857:                                Delete_upnphttp(e);
                   1858:                        }
                   1859:                        e = next;
                   1860:                }
                   1861: 
                   1862:        }       /* end of main loop */
                   1863: 
                   1864: shutdown:
                   1865:        /* close out open sockets */
                   1866:        while(upnphttphead.lh_first != NULL)
                   1867:        {
                   1868:                e = upnphttphead.lh_first;
                   1869:                LIST_REMOVE(e, entries);
                   1870:                Delete_upnphttp(e);
                   1871:        }
                   1872: 
                   1873:        if (sudp >= 0) close(sudp);
                   1874:        if (shttpl >= 0) close(shttpl);
1.1.1.2   misho    1875: #ifdef ENABLE_IPV6
                   1876:        if (sudpv6 >= 0) close(sudpv6);
                   1877: #endif
                   1878: #ifdef USE_IFACEWATCHER
                   1879:        if(sifacewatcher >= 0) close(sifacewatcher);
                   1880: #endif
1.1       misho    1881: #ifdef ENABLE_NATPMP
1.1.1.2   misho    1882:        for(i=0; i<addr_count; i++) {
1.1       misho    1883:                if(snatpmp[i]>=0)
                   1884:                {
                   1885:                        close(snatpmp[i]);
                   1886:                        snatpmp[i] = -1;
                   1887:                }
                   1888:        }
                   1889: #endif
                   1890: #ifdef USE_MINIUPNPDCTL
                   1891:        if(sctl>=0)
                   1892:        {
                   1893:                close(sctl);
                   1894:                sctl = -1;
                   1895:                if(unlink("/var/run/miniupnpd.ctl") < 0)
                   1896:                {
                   1897:                        syslog(LOG_ERR, "unlink() %m");
                   1898:                }
                   1899:        }
                   1900: #endif
1.1.1.3 ! misho    1901: 
1.1       misho    1902:        if (GETFLAG(ENABLEUPNPMASK))
                   1903:        {
1.1.1.3 ! misho    1904: #ifndef ENABLE_IPV6
1.1.1.2   misho    1905:                if(SendSSDPGoodbye(snotify, addr_count) < 0)
1.1.1.3 ! misho    1906: #else
        !          1907:                if(SendSSDPGoodbye(snotify, addr_count * 2) < 0)
        !          1908: #endif
1.1       misho    1909:                {
                   1910:                        syslog(LOG_ERR, "Failed to broadcast good-bye notifications");
                   1911:                }
1.1.1.3 ! misho    1912: #ifndef ENABLE_IPV6
        !          1913:                for(i = 0; i < addr_count; i++)
        !          1914: #else
        !          1915:                for(i = 0; i < addr_count * 2; i++)
        !          1916: #endif
1.1       misho    1917:                        close(snotify[i]);
                   1918:        }
                   1919: 
1.1.1.3 ! misho    1920:        if(pidfilename && (unlink(pidfilename) < 0))
1.1       misho    1921:        {
                   1922:                syslog(LOG_ERR, "Failed to remove pidfile %s: %m", pidfilename);
                   1923:        }
                   1924: 
1.1.1.2   misho    1925:        /* delete lists */
                   1926:        while(lan_addrs.lh_first != NULL)
                   1927:        {
                   1928:                lan_addr = lan_addrs.lh_first;
                   1929:                LIST_REMOVE(lan_addrs.lh_first, list);
                   1930:                free(lan_addr);
                   1931:        }
                   1932: 
                   1933: #ifdef ENABLE_NATPMP
                   1934:        free(snatpmp);
                   1935: #endif
                   1936:        free(snotify);
1.1.1.3 ! misho    1937:        closelog();
        !          1938: #ifndef DISABLE_CONFIG_FILE
1.1       misho    1939:        freeoptions();
1.1.1.3 ! misho    1940: #endif
        !          1941: 
1.1       misho    1942:        return 0;
                   1943: }
                   1944: 

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