File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / miniupnpd / upnpredirect.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:55:57 2012 UTC (12 years, 2 months ago) by misho
Branches: miniupnpd, elwix, MAIN
CVS tags: v1_6elwix, HEAD
miniupnpd 1.6+patches

    1: /* $Id: upnpredirect.c,v 1.1.1.2 2012/05/29 12:55:57 misho Exp $ */
    2: /* MiniUPnP project
    3:  * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
    4:  * (c) 2006-2011 Thomas Bernard 
    5:  * This software is subject to the conditions detailed
    6:  * in the LICENCE file provided within the distribution */
    7: 
    8: #include <stdlib.h>
    9: #include <string.h>
   10: #include <syslog.h>
   11: #include <sys/types.h>
   12: #include <sys/socket.h>
   13: #include <netinet/in.h>
   14: #include <net/if.h>
   15: #include <arpa/inet.h>
   16: 
   17: #include <stdio.h>
   18: #include <ctype.h>
   19: #include <unistd.h>
   20: 
   21: #include "config.h"
   22: #include "upnpredirect.h"
   23: #include "upnpglobalvars.h"
   24: #include "upnpevents.h"
   25: #if defined(USE_NETFILTER)
   26: #include "netfilter/iptcrdr.h"
   27: #endif
   28: #if defined(USE_PF)
   29: #include "pf/obsdrdr.h"
   30: #endif
   31: #if defined(USE_IPF)
   32: #include "ipf/ipfrdr.h"
   33: #endif
   34: #if defined(USE_IPFW)
   35: #include "ipfw/ipfwrdr.h"
   36: #endif
   37: #ifdef USE_MINIUPNPDCTL
   38: #include <stdio.h>
   39: #include <unistd.h>
   40: #endif
   41: #ifdef ENABLE_LEASEFILE
   42: #include <sys/stat.h>
   43: #endif
   44: 
   45: /* from <inttypes.h> */
   46: #ifndef PRIu64
   47: #define PRIu64 "llu"
   48: #endif
   49: 
   50: /* proto_atoi() 
   51:  * convert the string "UDP" or "TCP" to IPPROTO_UDP and IPPROTO_UDP */
   52: static int
   53: proto_atoi(const char * protocol)
   54: {
   55: 	int proto = IPPROTO_TCP;
   56: 	if(strcmp(protocol, "UDP") == 0)
   57: 		proto = IPPROTO_UDP;
   58: 	return proto;
   59: }
   60: 
   61: #ifdef ENABLE_LEASEFILE
   62: static int
   63: lease_file_add(unsigned short eport,
   64:                const char * iaddr,
   65:                unsigned short iport,
   66:                int proto,
   67:                const char * desc,
   68:                unsigned int timestamp)
   69: {
   70: 	FILE * fd;
   71: 
   72: 	if (lease_file == NULL) return 0;
   73: 
   74: 	fd = fopen( lease_file, "a");
   75: 	if (fd==NULL) {
   76: 		syslog(LOG_ERR, "could not open lease file: %s", lease_file);
   77: 		return -1;
   78: 	}
   79: 
   80: 	fprintf(fd, "%s:%hu:%s:%hu:%u:%s\n",
   81: 	        ((proto==IPPROTO_TCP)?"TCP":"UDP"), eport, iaddr, iport,
   82: 	        timestamp, desc);
   83: 	fclose(fd);
   84: 	
   85: 	return 0;
   86: }
   87: 
   88: static int
   89: lease_file_remove(unsigned short eport, int proto)
   90: {
   91: 	FILE* fd, *fdt;
   92: 	int tmp;
   93: 	char buf[512];
   94: 	char str[32];
   95: 	char tmpfilename[128];
   96: 	int str_size, buf_size;
   97: 
   98: 
   99: 	if (lease_file == NULL) return 0;
  100: 
  101: 	if (strlen( lease_file) + 7 > sizeof(tmpfilename)) {
  102: 		syslog(LOG_ERR, "Lease filename is too long");
  103: 		return -1;
  104: 	}
  105: 
  106: 	strncpy( tmpfilename, lease_file, sizeof(tmpfilename) );
  107: 	strncat( tmpfilename, "XXXXXX", sizeof(tmpfilename) - strlen(tmpfilename));
  108: 
  109: 	fd = fopen( lease_file, "r");
  110: 	if (fd==NULL) {
  111: 		return 0;
  112: 	}
  113: 
  114: 	snprintf( str, sizeof(str), "%s:%u", ((proto==IPPROTO_TCP)?"TCP":"UDP"), eport);
  115: 	str_size = strlen(str);
  116: 
  117: 	tmp = mkstemp(tmpfilename);
  118: 	if (tmp==-1) {
  119: 		fclose(fd);
  120: 		syslog(LOG_ERR, "could not open temporary lease file");
  121: 		return -1;
  122: 	}
  123: 	fchmod(tmp, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  124: 	fdt = fdopen(tmp, "a");
  125: 
  126: 	buf[sizeof(buf)-1] = 0;
  127: 	while( fgets(buf, sizeof(buf)-1, fd) != NULL) {
  128: 		buf_size = strlen(buf);
  129: 
  130: 		if (buf_size < str_size || strncmp(str, buf, str_size)!=0) {
  131: 			fwrite(buf, buf_size, 1, fdt);
  132: 		}
  133: 	}
  134: 	fclose(fdt);
  135: 	fclose(fd);
  136: 	
  137: 	if (rename(tmpfilename, lease_file) < 0) {
  138: 		syslog(LOG_ERR, "could not rename temporary lease file to %s", lease_file);
  139: 		remove(tmpfilename);
  140: 	}
  141: 	
  142: 	return 0;
  143: 	
  144: }
  145: 
  146: /* reload_from_lease_file()
  147:  * read lease_file and add the rules contained
  148:  */
  149: int reload_from_lease_file()
  150: {
  151: 	FILE * fd;
  152: 	char * p;
  153: 	unsigned short eport, iport;
  154: 	char * proto;
  155: 	char * iaddr;
  156: 	char * desc;
  157: 	char * rhost;
  158: 	unsigned int leaseduration;
  159: 	unsigned int timestamp;
  160: 	time_t current_time;
  161: 	char line[128];
  162: 	int r;
  163: 
  164: 	if(!lease_file) return -1;
  165: 	fd = fopen( lease_file, "r");
  166: 	if (fd==NULL) {
  167: 		syslog(LOG_ERR, "could not open lease file: %s", lease_file);
  168: 		return -1;
  169: 	}
  170: 	if(unlink(lease_file) < 0) {
  171: 		syslog(LOG_WARNING, "could not unlink file %s : %m", lease_file);
  172: 	}
  173: 
  174: 	current_time = time(NULL);
  175: 	while(fgets(line, sizeof(line), fd)) {
  176: 		syslog(LOG_DEBUG, "parsing lease file line '%s'", line);
  177: 		proto = line;
  178: 		p = strchr(line, ':');
  179: 		if(!p) {
  180: 			syslog(LOG_ERR, "unrecognized data in lease file");
  181: 			continue;
  182: 		}
  183: 		*(p++) = '\0';
  184: 		iaddr = strchr(p, ':');
  185: 		if(!iaddr) {
  186: 			syslog(LOG_ERR, "unrecognized data in lease file");
  187: 			continue;
  188: 		}
  189: 		*(iaddr++) = '\0';
  190: 		eport = (unsigned short)atoi(p);
  191: 		p = strchr(iaddr, ':');
  192: 		if(!p) {
  193: 			syslog(LOG_ERR, "unrecognized data in lease file");
  194: 			continue;
  195: 		}
  196: 		*(p++) = '\0';
  197: 		timestamp = (unsigned int)atoi(p);
  198: 		p = strchr(p, ':');
  199: 		if(!p) {
  200: 			syslog(LOG_ERR, "unrecognized data in lease file");
  201: 			continue;
  202: 		}
  203: 		*(p++) = '\0';
  204: 		desc = strchr(p, ':');
  205: 		if(!desc) {
  206: 			syslog(LOG_ERR, "unrecognized data in lease file");
  207: 			continue;
  208: 		}
  209: 		*(desc++) = '\0';
  210: 		iport = (unsigned short)atoi(p);
  211: 		/* trim description */
  212: 		while(isspace(*desc))
  213: 			desc++;
  214: 		p = desc;
  215: 		while(*(p+1))
  216: 			p++;
  217: 		while(isspace(*p) && (p > desc))
  218: 			*(p--) = '\0';
  219: 
  220: 		if(timestamp > 0) {
  221: 			if(timestamp <= current_time) {
  222: 				syslog(LOG_NOTICE, "already expired lease in lease file");
  223: 				continue;
  224: 			} else {
  225: 				leaseduration = current_time - timestamp;
  226: 			}
  227: 		} else {
  228: 			leaseduration = 0;	/* default value */
  229: 		}
  230: 		rhost = NULL;
  231: 		r = upnp_redirect(rhost, eport, iaddr, iport, proto, desc, leaseduration);
  232: 		if(r == -1) {
  233: 			syslog(LOG_ERR, "Failed to redirect %hu -> %s:%hu protocol %s",
  234: 			       eport, iaddr, iport, proto);
  235: 		} else if(r == -2) {
  236: 			/* Add the redirection again to the lease file */
  237: 			lease_file_add(eport, iaddr, iport, proto_atoi(proto),
  238: 			               desc, timestamp);
  239: 		}
  240: 	}
  241: 	fclose(fd);
  242: 	
  243: 	return 0;
  244: }
  245: #endif
  246: 
  247: /* upnp_redirect() 
  248:  * calls OS/fw dependant implementation of the redirection.
  249:  * protocol should be the string "TCP" or "UDP"
  250:  * returns: 0 on success
  251:  *          -1 failed to redirect
  252:  *          -2 already redirected
  253:  *          -3 permission check failed
  254:  */
  255: int
  256: upnp_redirect(const char * rhost, unsigned short eport, 
  257:               const char * iaddr, unsigned short iport,
  258:               const char * protocol, const char * desc,
  259:               unsigned int leaseduration)
  260: {
  261: 	int proto, r;
  262: 	char iaddr_old[32];
  263: 	unsigned short iport_old;
  264: 	struct in_addr address;
  265: 	unsigned int timestamp;
  266: 
  267: 	proto = proto_atoi(protocol);
  268: 	if(inet_aton(iaddr, &address) < 0) {
  269: 		syslog(LOG_ERR, "inet_aton(%s) : %m", iaddr);
  270: 		return -1;
  271: 	}
  272: 
  273: 	if(!check_upnp_rule_against_permissions(upnppermlist, num_upnpperm,
  274: 	                                        eport, address, iport)) {
  275: 		syslog(LOG_INFO, "redirection permission check failed for "
  276: 		                 "%hu->%s:%hu %s", eport, iaddr, iport, protocol);
  277: 		return -3;
  278: 	}
  279: 	r = get_redirect_rule(ext_if_name, eport, proto,
  280: 	                      iaddr_old, sizeof(iaddr_old), &iport_old, 0, 0,
  281: 	                      0, 0,
  282: 	                      &timestamp, 0, 0);
  283: 	if(r == 0) {
  284: 		/* if existing redirect rule matches redirect request return success
  285: 		 * xbox 360 does not keep track of the port it redirects and will
  286: 		 * redirect another port when receiving ConflictInMappingEntry */
  287: 		if(strcmp(iaddr, iaddr_old)==0 && iport==iport_old) {
  288: 			syslog(LOG_INFO, "ignoring redirect request as it matches existing redirect");
  289: 		} else {
  290: 
  291: 			syslog(LOG_INFO, "port %hu protocol %s already redirected to %s:%hu",
  292: 				eport, protocol, iaddr_old, iport_old);
  293: 			return -2;
  294: 		}
  295: 	} else {
  296: 		timestamp = (leaseduration > 0) ? time(NULL) + leaseduration : 0;
  297: 		syslog(LOG_INFO, "redirecting port %hu to %s:%hu protocol %s for: %s",
  298: 			eport, iaddr, iport, protocol, desc);			
  299: 		return upnp_redirect_internal(rhost, eport, iaddr, iport, proto,
  300: 		                              desc, timestamp);
  301: 	}
  302: 
  303: 	return 0;
  304: }
  305: 
  306: int
  307: upnp_redirect_internal(const char * rhost, unsigned short eport,
  308:                        const char * iaddr, unsigned short iport,
  309:                        int proto, const char * desc,
  310:                        unsigned int timestamp)
  311: {
  312: 	/*syslog(LOG_INFO, "redirecting port %hu to %s:%hu protocol %s for: %s",
  313: 		eport, iaddr, iport, protocol, desc);			*/
  314: 	if(add_redirect_rule2(ext_if_name, rhost, eport, iaddr, iport, proto,
  315: 	                      desc, timestamp) < 0) {
  316: 		return -1;
  317: 	}
  318: 
  319: #ifdef ENABLE_LEASEFILE
  320: 	lease_file_add( eport, iaddr, iport, proto, desc, timestamp);
  321: #endif
  322: /*	syslog(LOG_INFO, "creating pass rule to %s:%hu protocol %s for: %s",
  323: 		iaddr, iport, protocol, desc);*/
  324: 	if(add_filter_rule2(ext_if_name, rhost, iaddr, eport, iport, proto, desc) < 0) {
  325: 		/* clean up the redirect rule */
  326: #if !defined(__linux__)
  327: 		delete_redirect_rule(ext_if_name, eport, proto);
  328: #endif
  329: 		return -1;
  330: 	}
  331: 	if(timestamp > 0) {
  332: 		if(!nextruletoclean_timestamp || (timestamp < nextruletoclean_timestamp))
  333: 			nextruletoclean_timestamp = timestamp;
  334: 	}
  335: #ifdef ENABLE_EVENTS
  336: 	/* the number of port mappings changed, we must
  337: 	 * inform the subscribers */
  338: 	upnp_event_var_change_notify(EWanIPC);
  339: #endif
  340: 	return 0;
  341: }
  342: 
  343: 
  344: 
  345: /* Firewall independant code which call the FW dependant code. */
  346: int
  347: upnp_get_redirection_infos(unsigned short eport, const char * protocol,
  348:                            unsigned short * iport,
  349:                            char * iaddr, int iaddrlen,
  350:                            char * desc, int desclen,
  351:                            char * rhost, int rhostlen,
  352:                            unsigned int * leaseduration)
  353: {
  354: 	int r;
  355: 	unsigned int timestamp;
  356: 	time_t current_time;
  357: 
  358: 	if(desc && (desclen > 0))
  359: 		desc[0] = '\0';
  360: 	if(rhost && (rhostlen > 0))
  361: 		rhost[0] = '\0';
  362: 	r = get_redirect_rule(ext_if_name, eport, proto_atoi(protocol),
  363: 	                      iaddr, iaddrlen, iport, desc, desclen,
  364: 	                      rhost, rhostlen, &timestamp,
  365: 	                      0, 0);
  366: 	if(r == 0 && timestamp > 0 && timestamp > (current_time = time(NULL))) {
  367: 		*leaseduration = timestamp - current_time;
  368: 	} else {
  369: 		*leaseduration = 0;
  370: 	}
  371: 	return r;
  372: }
  373: 
  374: int
  375: upnp_get_redirection_infos_by_index(int index,
  376:                                     unsigned short * eport, char * protocol,
  377:                                     unsigned short * iport, 
  378:                                     char * iaddr, int iaddrlen,
  379:                                     char * desc, int desclen,
  380:                                     char * rhost, int rhostlen,
  381:                                     unsigned int * leaseduration)
  382: {
  383: 	/*char ifname[IFNAMSIZ];*/
  384: 	int proto = 0;
  385: 	unsigned int timestamp;
  386: 	time_t current_time;
  387: 
  388: 	if(desc && (desclen > 0))
  389: 		desc[0] = '\0';
  390: 	if(rhost && (rhost > 0))
  391: 		rhost[0] = '\0';
  392: 	if(get_redirect_rule_by_index(index, 0/*ifname*/, eport, iaddr, iaddrlen,
  393: 	                              iport, &proto, desc, desclen,
  394: 	                              rhost, rhostlen, &timestamp,
  395: 	                              0, 0) < 0)
  396: 		return -1;
  397: 	else
  398: 	{
  399: 		current_time = time(NULL);
  400: 		*leaseduration = (timestamp > current_time)
  401: 		                 ? (timestamp - current_time)
  402: 		                 : 0;
  403: 		if(proto == IPPROTO_TCP)
  404: 			memcpy(protocol, "TCP", 4);
  405: 		else
  406: 			memcpy(protocol, "UDP", 4);
  407: 		return 0;
  408: 	}
  409: }
  410: 
  411: /* called from natpmp.c too */
  412: int
  413: _upnp_delete_redir(unsigned short eport, int proto)
  414: {
  415: 	int r;
  416: #if defined(__linux__)
  417: 	r = delete_redirect_and_filter_rules(eport, proto);
  418: #else
  419: 	r = delete_redirect_rule(ext_if_name, eport, proto);
  420: 	delete_filter_rule(ext_if_name, eport, proto);
  421: #endif
  422: #ifdef ENABLE_LEASEFILE
  423: 	lease_file_remove( eport, proto);
  424: #endif
  425: 
  426: #ifdef ENABLE_EVENTS
  427: 	upnp_event_var_change_notify(EWanIPC);
  428: #endif
  429: 	return r;
  430: }
  431: 
  432: int
  433: upnp_delete_redirection(unsigned short eport, const char * protocol)
  434: {
  435: 	syslog(LOG_INFO, "removing redirect rule port %hu %s", eport, protocol);
  436: 	return _upnp_delete_redir(eport, proto_atoi(protocol));
  437: }
  438: 
  439: /* upnp_get_portmapping_number_of_entries()
  440:  * TODO: improve this code. */
  441: int
  442: upnp_get_portmapping_number_of_entries()
  443: {
  444: 	int n = 0, r = 0;
  445: 	unsigned short eport, iport;
  446: 	char protocol[4], iaddr[32], desc[64], rhost[32];
  447: 	unsigned int leaseduration;
  448: 	do {
  449: 		protocol[0] = '\0'; iaddr[0] = '\0'; desc[0] = '\0';
  450: 		r = upnp_get_redirection_infos_by_index(n, &eport, protocol, &iport,
  451: 		                                        iaddr, sizeof(iaddr),
  452: 		                                        desc, sizeof(desc),
  453: 		                                        rhost, sizeof(rhost),
  454: 		                                        &leaseduration);
  455: 		n++;
  456: 	} while(r==0);
  457: 	return (n-1);
  458: }
  459: 
  460: /* functions used to remove unused rules
  461:  * As a side effect, delete expired rules (based on LeaseDuration) */
  462: struct rule_state *
  463: get_upnp_rules_state_list(int max_rules_number_target)
  464: {
  465: 	/*char ifname[IFNAMSIZ];*/
  466: 	int proto;
  467: 	unsigned short iport;
  468: 	unsigned int timestamp;
  469: 	struct rule_state * tmp;
  470: 	struct rule_state * list = 0;
  471: 	struct rule_state * * p;
  472: 	int i = 0;
  473: 	time_t current_time;
  474: 
  475: 	/*ifname[0] = '\0';*/
  476: 	tmp = malloc(sizeof(struct rule_state));
  477: 	if(!tmp)
  478: 		return 0;
  479: 	current_time = time(NULL);
  480: 	nextruletoclean_timestamp = 0;
  481: 	while(get_redirect_rule_by_index(i, /*ifname*/0, &tmp->eport, 0, 0,
  482: 	                              &iport, &proto, 0, 0, 0,0, &timestamp,
  483: 								  &tmp->packets, &tmp->bytes) >= 0)
  484: 	{
  485: 		tmp->to_remove = 0;
  486: 		if(timestamp > 0) {
  487: 			/* need to remove this port mapping ? */
  488: 			if(timestamp <= current_time)
  489: 				tmp->to_remove = 1;
  490: 			else if((nextruletoclean_timestamp <= current_time)
  491: 			       || (timestamp < nextruletoclean_timestamp))
  492: 				nextruletoclean_timestamp = timestamp;
  493: 		}
  494: 		tmp->proto = (short)proto;
  495: 		/* add tmp to list */
  496: 		tmp->next = list;
  497: 		list = tmp;
  498: 		/* prepare next iteration */
  499: 		i++;
  500: 		tmp = malloc(sizeof(struct rule_state));
  501: 		if(!tmp)
  502: 			break;
  503: 	}
  504: 	free(tmp);
  505: 	/* remove the redirections that need to be removed */
  506: 	for(p = &list, tmp = list; tmp; tmp = *p)
  507: 	{
  508: 		if(tmp->to_remove)
  509: 		{
  510: 			syslog(LOG_NOTICE, "remove port mapping %hu %s because it has expired",
  511: 			       tmp->eport, (tmp->proto==IPPROTO_TCP)?"TCP":"UDP");
  512: 			_upnp_delete_redir(tmp->eport, tmp->proto);
  513: 			*p = tmp->next;
  514: 			free(tmp);
  515: 			i--;
  516: 		} else {
  517: 			p = &(tmp->next);
  518: 		}
  519: 	}
  520: 	/* return empty list if not enough redirections */
  521: 	if(i<=max_rules_number_target)
  522: 		while(list)
  523: 		{
  524: 			tmp = list;
  525: 			list = tmp->next;
  526: 			free(tmp);
  527: 		}
  528: 	/* return list */
  529: 	return list;
  530: }
  531: 
  532: void
  533: remove_unused_rules(struct rule_state * list)
  534: {
  535: 	char ifname[IFNAMSIZ];
  536: 	unsigned short iport;
  537: 	struct rule_state * tmp;
  538: 	u_int64_t packets;
  539: 	u_int64_t bytes;
  540: 	unsigned int timestamp;
  541: 	int n = 0;
  542: 
  543: 	while(list)
  544: 	{
  545: 		/* remove the rule if no traffic has used it */
  546: 		if(get_redirect_rule(ifname, list->eport, list->proto,
  547: 	                         0, 0, &iport, 0, 0, 0, 0, &timestamp,
  548: 		                     &packets, &bytes) >= 0)
  549: 		{
  550: 			if(packets == list->packets && bytes == list->bytes)
  551: 			{
  552: 				_upnp_delete_redir(list->eport, list->proto);
  553: 				n++;
  554: 			}
  555: 		}
  556: 		tmp = list;
  557: 		list = tmp->next;
  558: 		free(tmp);
  559: 	}
  560: 	if(n>0)
  561: 		syslog(LOG_NOTICE, "removed %d unused rules", n);
  562: }
  563: 
  564: /* upnp_get_portmappings_in_range()
  565:  * return a list of all "external" ports for which a port
  566:  * mapping exists */
  567: unsigned short *
  568: upnp_get_portmappings_in_range(unsigned short startport,
  569:                                unsigned short endport,
  570:                                const char * protocol,
  571:                                unsigned int * number)
  572: {
  573: 	int proto;
  574: 	proto = proto_atoi(protocol);
  575: 	if(!number)
  576: 		return NULL;
  577: 	return get_portmappings_in_range(startport, endport, proto, number);
  578: }
  579: 
  580: #ifdef ENABLE_6FC_SERVICE
  581: int
  582: upnp_check_outbound_pinhole(int proto, int * timeout)
  583: {
  584: #if 0
  585: 	int s, tmptimeout, tmptime_out;
  586: 	switch(proto)
  587: 	{
  588: 		case IPPROTO_UDP:
  589: 			s = retrieve_timeout("udp_timeout", timeout);
  590: 			return s;
  591: 			break;
  592: 		case IPPROTO_UDPLITE:
  593: 			s = retrieve_timeout("udp_timeout_stream", timeout);
  594: 			return s;
  595: 			break;
  596: 		case IPPROTO_TCP:
  597: 			s = retrieve_timeout("tcp_timeout_established", timeout);
  598: 			return s;
  599: 			break;
  600: 		case 65535:
  601: 			s = retrieve_timeout("udp_timeout", timeout);
  602: 			s = retrieve_timeout("udp_timeout_stream", &tmptimeout);
  603: 			s = retrieve_timeout("tcp_timeout_established", &tmptime_out);
  604: 			if(tmptimeout<tmptime_out)
  605: 			{
  606: 				if(tmptimeout<*timeout)
  607: 					*timeout = tmptimeout;
  608: 			}
  609: 			else
  610: 			{
  611: 				if(tmptime_out<*timeout)
  612: 					*timeout = tmptimeout;
  613: 			}
  614: 			return s;
  615: 			break;
  616: 		default:
  617: 			return -5;
  618: 			break;
  619: 	}
  620: #endif
  621: 	return 0;
  622: }
  623: 
  624: /* upnp_add_inboundpinhole()
  625:  * returns: 0 on success
  626:  *          -1 failed to add pinhole
  627:  *          -2 already created
  628:  *          -3 inbound pinhole disabled
  629:  */
  630: int
  631: upnp_add_inboundpinhole(const char * raddr,
  632:                         unsigned short rport,
  633:                         const char * iaddr,
  634:                         unsigned short iport,
  635:                         const char * protocol,
  636:                         const char * leaseTime,
  637:                         int * uid)
  638: {
  639: 	int r, s, t, lt=0;
  640: 	char iaddr_old[40]="", proto[6]="", idfound[5]="", leaseTmp[12]; // IPv6 Modification
  641: 	snprintf(proto, sizeof(proto), "%.5d", atoi(protocol));
  642: 	unsigned short iport_old = 0;
  643: 	time_t current = time(NULL);
  644: 	/*struct in6_addr address; // IPv6 Modification
  645: 	if(inet_pton(AF_INET6, iaddr, &address) < 0) // IPv6 Modification
  646: 	{
  647: 		syslog(LOG_ERR, "inet_pton(%s) : %m", iaddr);
  648: 		return 0;
  649: 	}*/
  650: 
  651: #if 0
  652: 	r = get_rule_from_file(raddr, rport, iaddr_old, &iport_old, proto, 0, 0, idfound);
  653: #endif
  654: 	r = 0;
  655: 
  656: 	lt = (int) current + atoi(leaseTime);
  657: 	snprintf(leaseTmp, sizeof(leaseTmp), "%d", lt);
  658: 	printf("LeaseTime: %d / %d -> %s\n", atoi(leaseTime), (int)current, leaseTmp);
  659: 
  660: 	printf("\tCompare addr: %s // port: %d\n\t     to addr: %s // port: %d\n", iaddr, iport, iaddr_old, iport_old);
  661: 	if(r == 1 && strcmp(iaddr, iaddr_old)==0 && iport==iport_old)
  662: 	{
  663: 		syslog(LOG_INFO, "Pinhole for inbound traffic from [%s]:%hu to [%s]:%hu with protocol %s already done. Updating it.", raddr, rport, iaddr_old, iport_old, protocol);
  664: 		t = upnp_update_inboundpinhole(idfound, leaseTime);
  665: 		*uid = atoi(idfound);
  666: 		return t;
  667: 	}
  668: 	else
  669: 	{
  670: 		syslog(LOG_INFO, "Adding pinhole for inbound traffic from [%s]:%hu to [%s]:%hu with protocol %s and %s lease time.", raddr, rport, iaddr, iport, protocol, leaseTime);
  671: 		s = upnp_add_inboundpinhole_internal(raddr, rport, iaddr, iport, protocol, uid);
  672: #if 0
  673: 		if(rule_file_add(raddr, rport, iaddr, iport, protocol, leaseTmp, uid)<0)
  674: 			return -8;
  675: 		else
  676: 		{
  677: 			if(nextpinholetoclean_timestamp == 0 || (atoi(leaseTmp) <= nextpinholetoclean_timestamp))
  678: 			{
  679: 				printf("Initializing the nextpinholetoclean variables. uid = %d\n", *uid);
  680: 				snprintf(nextpinholetoclean_uid, 5, "%.4d", *uid);
  681: 				nextpinholetoclean_timestamp = atoi(leaseTmp);
  682: 			}
  683: 			return s;
  684: 		}
  685: #endif
  686: 	}
  687: return 0;
  688: }
  689: 
  690: int
  691: upnp_add_inboundpinhole_internal(const char * raddr, unsigned short rport,
  692:                        const char * iaddr, unsigned short iport,
  693:                        const char * proto, int * uid)
  694: {
  695: 	int c = 9999;
  696: 	char cmd[256], cmd_raw[256], cuid[42];
  697: #if 0
  698: 	static const char cmdval_full_udptcp[] = "ip6tables -I %s %d -p %s -i %s -s %s --sport %hu -d %s --dport %hu -j ACCEPT";
  699: 	static const char cmdval_udptcp[] = "ip6tables -I %s %d -p %s -i %s --sport %hu -d %s --dport %hu -j ACCEPT";
  700: 	static const char cmdval_full_udplite[] = "ip6tables -I %s %d -p %s -i %s -s %s -d %s -j ACCEPT";
  701: 	static const char cmdval_udplite[] = "ip6tables -I %s %d -p %s -i %s -d %s -j ACCEPT";
  702: 	// raw table command
  703: 	static const char cmdval_full_udptcp_raw[] = "ip6tables -t raw -I PREROUTING %d -p %s -i %s -s %s --sport %hu -d %s --dport %hu -j TRACE";
  704: 	static const char cmdval_udptcp_raw[] = "ip6tables -t raw -I PREROUTING %d -p %s -i %s --sport %hu -d %s --dport %hu -j TRACE";
  705: 	static const char cmdval_full_udplite_raw[] = "ip6tables -t raw -I PREROUTING %d -p %s -i %s -s %s -d %s -j TRACE";
  706: 	static const char cmdval_udplite_raw[] = "ip6tables -t raw -I PREROUTING %d -p %s -i %s -d %s -j TRACE";
  707: #endif
  708: 	//printf("%s\n", raddr);
  709: 	if(raddr!=NULL)
  710: 	{
  711: #ifdef IPPROTO_UDPLITE
  712: 		if(atoi(proto) == IPPROTO_UDPLITE)
  713: 		{
  714: 	/*		snprintf(cmd, sizeof(cmd), cmdval_full_udplite, miniupnpd_forward_chain, line_number, proto, ext_if_name, raddr, iaddr);
  715: 			snprintf(cmd_raw, sizeof(cmd_raw), cmdval_full_udplite_raw, line_number, proto, ext_if_name, raddr, iaddr);*/
  716: 		}
  717: 		else
  718: #endif
  719: 		{
  720: 	/*		snprintf(cmd, sizeof(cmd), cmdval_full_udptcp, miniupnpd_forward_chain, line_number, proto, ext_if_name, raddr, rport, iaddr, iport);
  721: 			snprintf(cmd_raw, sizeof(cmd_raw), cmdval_full_udptcp_raw, line_number, proto, ext_if_name, raddr, rport, iaddr, iport);*/
  722: 		}
  723: 	}
  724: 	else
  725: 	{
  726: #ifdef IPPROTO_UDPLITE
  727: 		if(atoi(proto) == IPPROTO_UDPLITE)
  728: 		{
  729: 			/*snprintf(cmd, sizeof(cmd), cmdval_udplite, miniupnpd_forward_chain, line_number, proto, ext_if_name, iaddr);
  730: 			snprintf(cmd_raw, sizeof(cmd_raw), cmdval_udplite_raw, line_number, proto, ext_if_name, iaddr);*/
  731: 		}
  732: 		else
  733: #endif
  734: 		{
  735: 			/*snprintf(cmd, sizeof(cmd), cmdval_udptcp, miniupnpd_forward_chain, line_number, proto, ext_if_name, rport, iaddr, iport);
  736: 			snprintf(cmd_raw, sizeof(cmd_raw), cmdval_udptcp_raw, line_number, proto, ext_if_name, rport, iaddr, iport);
  737: */
  738: 		}
  739: 	}
  740: #ifdef DEBUG
  741: 	syslog(LOG_INFO, "Adding following ip6tables rule:");
  742: 	syslog(LOG_INFO, "  -> %s", cmd);
  743: 	syslog(LOG_INFO, "  -> %s", cmd_raw);
  744: #endif
  745: 	// TODO Add a better checking error.
  746: 	if(system(cmd) < 0 || system(cmd_raw) < 0)
  747: 	{
  748: 		return 0;
  749: 	}
  750: 	srand(time(NULL));
  751: 	snprintf(cuid, sizeof(cuid), "%.4d", rand()%c);
  752: 	*uid = atoi(cuid);
  753: 	printf("\t_add_ uid: %s\n", cuid);
  754: 	return 1;
  755: }
  756: 
  757: int
  758: upnp_get_pinhole_info(const char * raddr,
  759:                       unsigned short rport,
  760:                       char * iaddr,
  761:                       unsigned short * iport,
  762:                       char * proto,
  763:                       const char * uid,
  764:                       char * lt)
  765: {
  766: 	/* TODO : to be done
  767: 	 * Call Firewall specific code to get IPv6 pinhole infos */
  768: 	return 0;
  769: }
  770: 
  771: int
  772: upnp_update_inboundpinhole(const char * uid, const char * leasetime)
  773: {
  774: 	/* TODO : to be implemented */
  775: #if 0
  776: 	int r, n;
  777: 	syslog(LOG_INFO, "Updating pinhole for inbound traffic with ID: %s", uid);
  778: 	r = check_rule_from_file(uid, 0);
  779: 	if(r < 0)
  780: 		return r;
  781: 	else
  782: 	{
  783: 		n = rule_file_update(uid, leasetime);
  784: 		upnp_update_expiredpinhole();
  785: 		return n;
  786: 	}
  787: #else
  788: 	return -1;
  789: #endif
  790: }
  791: 
  792: int
  793: upnp_delete_inboundpinhole(const char * uid)
  794: {
  795: 	/* TODO : to be implemented */
  796: #if 0
  797: 	/* this is a alpha implementation calling ip6tables via system(), 
  798: 	 * it can be usefull as an example to code the netfilter version */
  799: 	int r, s, linenum=0;
  800: 	char cmd[256], cmd_raw[256];
  801: 	syslog(LOG_INFO, "Removing pinhole for inbound traffic with ID: %s", uid);
  802: 	r = check_rule_from_file(uid, &linenum);
  803: 	if(r > 0)
  804: 	{
  805: 		s = rule_file_remove(uid, linenum);
  806: 		if(s < 0)
  807: 			return s;
  808: 		else
  809: 		{
  810: 			snprintf(cmd, sizeof(cmd), "ip6tables -t filter -D %s %d", miniupnpd_forward_chain, linenum);
  811: 			snprintf(cmd_raw, sizeof(cmd_raw), "ip6tables -t raw -D PREROUTING %d", linenum -1);
  812: #ifdef DEBUG
  813: 			syslog(LOG_INFO, "Deleting ip6tables rule:");
  814: 			syslog(LOG_INFO, "  -> %s", cmd);
  815: 			syslog(LOG_INFO, "  -> %s", cmd_raw);
  816: #endif
  817: 			// TODO Add a better checking error.
  818: 			if(system(cmd) < 0 || system(cmd_raw) < 0)
  819: 			{
  820: 				return 0;
  821: 			}
  822: 		}
  823: 	}
  824: 	upnp_update_expiredpinhole();
  825: 	return r;
  826: #else
  827: return -1;
  828: #endif
  829: }
  830: 
  831: /*
  832:  * Result:
  833:  * 	 1: Found Result
  834:  * 	-4: No result
  835:  * 	-5: Result in another table
  836:  * 	-6: Result in another chain
  837:  * 	-7: Result in a chain not a rule
  838: */
  839: int
  840: upnp_check_pinhole_working(const char * uid,
  841:                            char * eaddr,
  842:                            char * iaddr,
  843:                            unsigned short * eport,
  844:                            unsigned short * iport,
  845:                            char * protocol,
  846:                            int * rulenum_used)
  847: {
  848: 	/* TODO : to be implemented */
  849: #if 0
  850: 	FILE * fd;
  851: 	time_t expire = time(NULL);
  852: 	char buf[1024], filename[] = "/var/log/kern.log", expire_time[32]="";
  853: 	int res = -4, str_len;
  854: 
  855: 	str_len = strftime(expire_time, sizeof(expire_time), "%b %d %H:%M:%S", localtime(&expire));
  856: 
  857: 	fd = fopen(filename, "r");
  858: 	if (fd==NULL)
  859: 	{
  860: 		syslog(LOG_ERR, "Get_rule: could not open file: %s", filename);
  861: 		return -1;
  862: 	}
  863: 
  864: 	syslog(LOG_INFO, "Get_rule: Starting getting info in file %s for %s\n", filename, uid);
  865: 	buf[sizeof(buf)-1] = 0;
  866: 	while(fgets(buf, sizeof(buf)-1, fd) != NULL && res != 1)
  867: 	{
  868: 		//printf("line: %s\n", buf);
  869: 		char * r, * t, * c, * p;
  870: 		// looking for something like filter:FORWARD:rule: or filter:MINIUPNPD:rule:
  871: 		r = strstr(buf, ":rule:");
  872: 		p = strstr(buf, ":policy:");
  873: 		t = strstr(buf, "TRACE:"); // table pointeur
  874: 		t += 7;
  875: 		c = t + 7; // chain pointeur
  876: 		if(r)
  877: 		{
  878: 			printf("\t** Found %.*s\n", 24 ,t);
  879: 			char * src, * dst, * sport, * dport, * proto, * line;
  880: 			char time[15]="", src_addr[40], dst_addr[40], proto_tmp[8];
  881: 			int proto_int;
  882: 			strncpy(time, buf, sizeof(time));
  883: 			/*if(compare_time(time, expire_time)<0)
  884: 			{
  885: 				printf("\t\tNot corresponding time\n");
  886: 				continue;
  887: 			}*/
  888: 
  889: 			line = r + 6;
  890: 			printf("\trule line = %d\n", atoi(line));
  891: 
  892: 			src = strstr(buf, "SRC=");
  893: 			src += 4;
  894: 			snprintf(src_addr, sizeof(src_addr), "%.*s", 39, src);
  895: #if 0
  896: 			del_char(src_addr);
  897: 			add_char(src_addr);
  898: #endif
  899: 
  900: 			dst = strstr(buf, "DST=");
  901: 			dst += 4;
  902: 			snprintf(dst_addr, sizeof(dst_addr), "%.*s", 39, dst);
  903: #if 0
  904: 			del_char(dst_addr);
  905: 			add_char(dst_addr);
  906: #endif
  907: 
  908: 			proto = strstr(buf, "PROTO=");
  909: 			proto += 6;
  910: 			proto_int = atoi(protocol);
  911: 			if(proto_int == IPPROTO_UDP)
  912: 				strcpy(proto_tmp, "UDP");
  913: 			else if(proto_int == IPPROTO_TCP)
  914: 				strcpy(proto_tmp, "TCP");
  915: #ifdef IPPROTO_UDPLITE
  916: 			else if(proto_int == IPPROTO_UDPLITE)
  917: 				strcpy(proto_tmp, "UDPLITE");
  918: #endif
  919: 			else
  920: 				strcpy(proto_tmp, "UnsupportedProto");
  921: 
  922: 	//		printf("\tCompare eaddr: %s // protocol: %s\n\t     to  addr: %s // protocol: %.*s\n", eaddr, proto_tmp, src_addr, strlen(proto_tmp), proto);
  923: 	//		printf("\tCompare iaddr: %s // protocol: %s\n\t     to  addr: %s // protocol: %.*s\n", iaddr, proto_tmp, dst_addr, strlen(proto_tmp), proto);
  924: 			// TODO Check time
  925: 			// Check that the paquet found in trace correspond to the one we are looking for
  926: 			if( /*(strcmp(eaddr, src_addr) == 0) &&*/ (strcmp(iaddr, dst_addr) == 0) && (strncmp(proto_tmp, proto, strlen(proto_tmp))==0))
  927: 			{
  928: 				sport = strstr(buf, "SPT=");
  929: 				sport += 4;
  930: 				dport = strstr(buf, "DPT=");
  931: 				dport += 4;
  932: 				printf("\tCompare eport: %hu\n\t     to   port: %d\n", *eport, atoi(sport));
  933: 				printf("\tCompare iport: %hu\n\t     to   port: %d\n", *iport, atoi(dport));
  934: 				if(/*eport != atoi(sport) &&*/ *iport != atoi(dport))
  935: 				{
  936: 					printf("\t\tPort not corresponding\n");
  937: 					continue;
  938: 				}
  939: 				printf("\ttable found: %.*s\n", 6, t);
  940: 				printf("\tchain found: %.*s\n", 9, c);
  941: 				// Check that the table correspond to the filter table
  942: 				if(strncmp(t, "filter", 6)==0)
  943: 				{
  944: 					// Check that the table correspond to the MINIUPNP table
  945: 					if(strncmp(c, "MINIUPNPD", 9)==0)
  946: 					{
  947: 						*rulenum_used = atoi(line);
  948: 						res = 1;
  949: 					}
  950: 					else
  951: 					{
  952: 						res = -6;
  953: 						continue;
  954: 					}
  955: 				}
  956: 				else
  957: 				{
  958: 					res = -5;
  959: 					continue;
  960: 				}
  961: 			}
  962: 			else
  963: 			{
  964: 				printf("Packet information not corresponding\n");
  965: 				continue;
  966: 			}
  967: 		}
  968: 		if(!r && p)
  969: 		{
  970: 			printf("\t** Policy case\n");
  971: 			char * src, * dst, * sport, * dport, * proto, * line;
  972: 			char time[15], src_addr[40], dst_addr[40], proto_tmp[8];
  973: 			int proto_int;
  974: 			strncpy(time, buf, sizeof(time));
  975: 			/*if(compare_time(time, expire_time)<0)
  976: 			{
  977: 				printf("\t\tNot corresponding time\n");
  978: 				continue;
  979: 			}*/
  980: 
  981: 			line = p + 8;
  982: 			printf("\trule line = %d\n", atoi(line));
  983: 
  984: 			src = strstr(buf, "SRC=");
  985: 			src += 4;
  986: 			snprintf(src_addr, sizeof(src_addr), "%.*s", 39, src);
  987: #if 0
  988: 			del_char(src_addr);
  989: 			add_char(src_addr);
  990: #endif
  991: 
  992: 			dst = strstr(buf, "DST=");
  993: 			dst += 4;
  994: 			snprintf(dst_addr, sizeof(dst_addr), "%.*s", 39, dst);
  995: #if 0
  996: 			del_char(dst_addr);
  997: 			add_char(dst_addr);
  998: #endif
  999: 
 1000: 			proto = strstr(buf, "PROTO=");
 1001: 			proto += 6;
 1002: 			proto_int = atoi(protocol);
 1003: 			if(proto_int == IPPROTO_UDP)
 1004: 				strcpy(proto_tmp, "UDP");
 1005: 			else if(proto_int == IPPROTO_TCP)
 1006: 				strcpy(proto_tmp, "TCP");
 1007: #ifdef IPPROTO_UDPLITE
 1008: 			else if(proto_int == IPPROTO_UDPLITE)
 1009: 				strcpy(proto_tmp, "UDPLITE");
 1010: #endif
 1011: 			else
 1012: 				strcpy(proto_tmp, "UnsupportedProto");
 1013: 
 1014: 	//		printf("\tCompare eaddr: %s // protocol: %s\n\t     to  addr: %s // protocol: %.*s\n", eaddr, proto_tmp, src_addr, strlen(proto_tmp), proto);
 1015: 	//		printf("\tCompare iaddr: %s // protocol: %s\n\t     to  addr: %s // protocol: %.*s\n", iaddr, proto_tmp, dst_addr, strlen(proto_tmp), proto);
 1016: 			// Check that the paquet found in trace correspond to the one we are looking for
 1017: 			if( (strcmp(eaddr, src_addr) == 0) && (strcmp(iaddr, dst_addr) == 0) && (strncmp(proto_tmp, proto, 5)==0))
 1018: 			{
 1019: 				sport = strstr(buf, "SPT=");
 1020: 				sport += 4;
 1021: 				dport = strstr(buf, "DPT=");
 1022: 				dport += 4;
 1023: 				printf("\tCompare eport: %hu\n\t     to   port: %d\n", *eport, atoi(sport));
 1024: 				printf("\tCompare iport: %hu\n\t     to   port: %d\n", *iport, atoi(dport));
 1025: 				if(*eport != atoi(sport) && *iport != atoi(dport))
 1026: 				{
 1027: 					printf("\t\tPort not corresponding\n");
 1028: 					continue;
 1029: 				}
 1030: 				else
 1031: 				{
 1032: 					printf("Find a corresponding policy trace in the chain: %.*s\n", 10, c);
 1033: 					res = -7;
 1034: 					continue;
 1035: 				}
 1036: 			}
 1037: 			else
 1038: 				continue;
 1039: 		}
 1040: 	}
 1041: 	fclose(fd);
 1042: 	return res;
 1043: #else
 1044: 	return -4;
 1045: #endif
 1046: }
 1047: 
 1048: int
 1049: upnp_get_pinhole_packets(const char * uid, int * packets)
 1050: {
 1051: 	/* TODO : to be implemented */
 1052: #if 0
 1053: 	int line=0, r;
 1054: 	char cmd[256];
 1055: 	r = check_rule_from_file(uid, &line);
 1056: 	if(r < 0)
 1057: 		return r;
 1058: 	else
 1059: 	{
 1060: 		snprintf(cmd, sizeof(cmd), "ip6tables -L MINIUPNPD %d -v", line);
 1061: 		return retrieve_packets(cmd, &line, packets);
 1062: 	}
 1063: #else
 1064: 	return 0;
 1065: #endif
 1066: }
 1067: 
 1068: int
 1069: upnp_update_expiredpinhole(void)
 1070: {
 1071: #if 0
 1072: 	int r;
 1073: 	char uid[5], leaseTime[12];
 1074: 
 1075: 	r = get_rule_from_leasetime(uid, leaseTime);
 1076: 	if(r<0)
 1077: 		return r;
 1078: 	else
 1079: 	{
 1080: 		strcpy(nextpinholetoclean_uid, uid);
 1081: 		nextpinholetoclean_timestamp = atoi(leaseTime);
 1082: 		return 1;
 1083: 	}
 1084: #endif
 1085: 	return 0;
 1086: }
 1087: 
 1088: int
 1089: upnp_clean_expiredpinhole()
 1090: {
 1091: #if 0
 1092: 	upnp_delete_inboundpinhole(nextpinholetoclean_uid);
 1093: 
 1094: 	return upnp_update_expiredpinhole();
 1095: #endif
 1096: 	return 0;
 1097: }
 1098: #endif
 1099: 
 1100: /* stuff for miniupnpdctl */
 1101: #ifdef USE_MINIUPNPDCTL
 1102: void
 1103: write_ruleset_details(int s)
 1104: {
 1105: 	int proto = 0;
 1106: 	unsigned short eport, iport;
 1107: 	char desc[64];
 1108: 	char iaddr[32];
 1109: 	char rhost[32];
 1110: 	unsigned int timestamp;
 1111: 	u_int64_t packets;
 1112: 	u_int64_t bytes;
 1113: 	int i = 0;
 1114: 	char buffer[256];
 1115: 	int n;
 1116: 
 1117: 	write(s, "Ruleset :\n", 10);
 1118: 	while(get_redirect_rule_by_index(i, 0/*ifname*/, &eport, iaddr, sizeof(iaddr),
 1119: 	                                 &iport, &proto, desc, sizeof(desc),
 1120: 	                                 rhost, sizeof(rhost),
 1121: 	                                 &timestamp,
 1122: 	                                 &packets, &bytes) >= 0)
 1123: 	{
 1124: 		n = snprintf(buffer, sizeof(buffer),
 1125: 		             "%2d %s %s:%hu->%s:%hu "
 1126: 		             "'%s' %u %" PRIu64 " %" PRIu64 "\n",
 1127: 		             /*"'%s' %llu %llu\n",*/
 1128: 		             i, proto==IPPROTO_TCP?"TCP":"UDP", rhost,
 1129: 		             eport, iaddr, iport, desc, timestamp, packets, bytes);
 1130: 		write(s, buffer, n);
 1131: 		i++;
 1132: 	}
 1133: }
 1134: #endif
 1135: 

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