⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 miniupnpd.c

📁 miniupnpd可以在嵌入式linux中实现upnp功能
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: miniupnpd.c,v 1.108 2008/04/23 23:29:30 nanard Exp $ *//* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ * (c) 2006-2008 Thomas Bernard * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */#include <stdlib.h>#include <unistd.h>#include <string.h>#include <stdio.h>#include <ctype.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <fcntl.h>#include <sys/file.h>#include <syslog.h>#include <sys/time.h>#include <time.h>#include <signal.h>#include <sys/param.h>#if defined(sun)#include <kstat.h>#else/* for BSD's sysctl */#include <sys/sysctl.h>#endif/* unix sockets */#include "config.h"#ifdef USE_MINIUPNPDCTL#include <sys/un.h>#endif#include "upnpglobalvars.h"#include "upnphttp.h"#include "upnpdescgen.h"#include "miniupnpdpath.h"#include "getifaddr.h"#include "upnpsoap.h"#include "options.h"#include "minissdp.h"#include "upnpredirect.h"#include "miniupnpdtypes.h"#include "daemonize.h"#include "upnpevents.h"#ifdef ENABLE_NATPMP#include "natpmp.h"#endif#include "commonrdr.h"#ifdef USE_MINIUPNPDCTLstruct ctlelem {	int socket;	LIST_ENTRY(ctlelem) entries;};#endif/* MAX_LAN_ADDR : maximum number of interfaces * to listen to SSDP traffic *//*#define MAX_LAN_ADDR (4)*/static volatile int quitting = 0;/* OpenAndConfHTTPSocket() : * setup the socket used to handle incoming HTTP connections. */static intOpenAndConfHTTPSocket(unsigned short port){	int s;	int i = 1;	struct sockaddr_in listenname;	if( (s = socket(PF_INET, SOCK_STREAM, 0)) < 0)	{		syslog(LOG_ERR, "socket(http): %m");		return -1;	}	if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0)	{		syslog(LOG_WARNING, "setsockopt(http, SO_REUSEADDR): %m");	}	memset(&listenname, 0, sizeof(struct sockaddr_in));	listenname.sin_family = AF_INET;	listenname.sin_port = htons(port);	listenname.sin_addr.s_addr = htonl(INADDR_ANY);	if(bind(s, (struct sockaddr *)&listenname, sizeof(struct sockaddr_in)) < 0)	{		syslog(LOG_ERR, "bind(http): %m");		close(s);		return -1;	}	if(listen(s, 6) < 0)	{		syslog(LOG_ERR, "listen(http): %m");		close(s);		return -1;	}	return s;}/* Functions used to communicate with miniupnpdctl */#ifdef USE_MINIUPNPDCTLstatic intOpenAndConfCtlUnixSocket(const char * path){	struct sockaddr_un localun;	int s;	s = socket(AF_UNIX, SOCK_STREAM, 0);	localun.sun_family = AF_UNIX;	strncpy(localun.sun_path, path,	          sizeof(localun.sun_path));	if(bind(s, (struct sockaddr *)&localun,	        sizeof(struct sockaddr_un)) < 0)	{		syslog(LOG_ERR, "bind(sctl): %m");		close(s);		s = -1;	}	else if(listen(s, 5) < 0)	{		syslog(LOG_ERR, "listen(sctl): %m");		close(s);		s = -1;	}	return s;}static voidwrite_upnphttp_details(int fd, struct upnphttp * e){	char buffer[256];	int len;	while(e)	{		len = snprintf(buffer, sizeof(buffer),		               "%d %d %s req_buf=%p(%dbytes) res_buf=%p(%dbytes alloc)\n",		               e->socket, e->state, e->HttpVer,		               e->req_buf, e->req_buflen,		               e->res_buf, e->res_buf_alloclen);		write(fd, buffer, len);		e = e->entries.le_next;	}}static voidwrite_ctlsockets_list(int fd, struct ctlelem * e){	char buffer[256];	int len;	while(e)	{		len = snprintf(buffer, sizeof(buffer),		               "struct ctlelem: socket=%d\n", e->socket);		write(fd, buffer, len);		e = e->entries.le_next;	}}static voidwrite_option_list(int fd){	char buffer[256];	int len;	int i;	for(i=0; i<num_options; i++)	{		len = snprintf(buffer, sizeof(buffer),		               "opt=%02d %s\n",		               ary_options[i].id, ary_options[i].value);		write(fd, buffer, len);	}}#endif/* Handler for the SIGTERM signal (kill)  * SIGINT is also handled */static voidsigterm(int sig){	/*int save_errno = errno;*/	signal(sig, SIG_IGN);	/* Ignore this signal while we are quitting */	syslog(LOG_NOTICE, "received signal %d, good-bye", sig);	quitting = 1;	/*errno = save_errno;*/}/* record the startup time, for returning uptime */static voidset_startup_time(int sysuptime){	startup_time = time(NULL);	if(sysuptime)	{		/* use system uptime instead of daemon uptime */#if defined(__linux__)		char buff[64];		int uptime, fd;		fd = open("/proc/uptime", O_RDONLY);		if(fd < 0)		{			syslog(LOG_ERR, "open(\"/proc/uptime\" : %m");		}		else		{			memset(buff, 0, sizeof(buff));			read(fd, buff, sizeof(buff) - 1);			uptime = atoi(buff);			syslog(LOG_INFO, "system uptime is %d seconds", uptime);			close(fd);			startup_time -= uptime;		}#elif defined(SOLARIS_KSTATS)		kstat_ctl_t *kc;		kc = kstat_open();		if(kc != NULL)		{			kstat_t *ksp;			ksp = kstat_lookup(kc, "unix", 0, "system_misc");			if(ksp && (kstat_read(kc, ksp, NULL) != -1))			{				void *ptr = kstat_data_lookup(ksp, "boot_time");				if(ptr)					memcpy(&startup_time, ptr, sizeof(startup_time));				else					syslog(LOG_ERR, "cannot find boot_time kstat");			}			else				syslog(LOG_ERR, "cannot open kstats for unix/0/system_misc: %m");			kstat_close(kc);		}#else		struct timeval boottime;		size_t size = sizeof(boottime);		int name[2] = { CTL_KERN, KERN_BOOTTIME };		if(sysctl(name, 2, &boottime, &size, NULL, 0) < 0)		{			syslog(LOG_ERR, "sysctl(\"kern.boottime\") failed");		}		else		{			startup_time = boottime.tv_sec;		}#endif	}}/* structure containing variables used during "main loop" * that are filled during the init */struct runtime_vars {	/* LAN IP addresses for SSDP traffic and HTTP */	/* moved to global vars */	/*int n_lan_addr;*/	/*struct lan_addr_s lan_addr[MAX_LAN_ADDR];*/	int port;	/* HTTP Port */	int notify_interval;	/* seconds between SSDP announces */	/* unused rules cleaning related variables : */	int clean_ruleset_threshold;	/* threshold for removing unused rules */	int clean_ruleset_interval;		/* (minimum) interval between checks */};/* parselanaddr() * parse address with mask * ex: 192.168.1.1/24 * return value :  *    0 : ok *   -1 : error */static intparselanaddr(struct lan_addr_s * lan_addr, const char * str){	const char * p;	int nbits = 24;	int n;	p = str;	while(*p && *p != '/' && !isspace(*p))		p++;	n = p - str;	if(*p == '/')	{		nbits = atoi(++p);		while(*p && !isspace(*p))			p++;	}	if(n>15)	{		fprintf(stderr, "Error parsing address/mask : %s\n", str);		return -1;	}	memcpy(lan_addr->str, str, n);	lan_addr->str[n] = '\0';	if(!inet_aton(lan_addr->str, &lan_addr->addr))	{		fprintf(stderr, "Error parsing address/mask : %s\n", str);		return -1;	}	lan_addr->mask.s_addr = htonl(nbits ? (0xffffffff << (32 - nbits)) : 0);#ifdef MULTIPLE_EXTERNAL_IP	while(*p && isspace(*p))		p++;	if(*p) {		n = 0;		while(p[n] && !isspace(*p))			n++;		if(n<=15) {			memcpy(lan_addr->ext_ip_str, p, n);			lan_addr->ext_ip_str[n] = '\0';			if(!inet_aton(lan_addr->ext_ip_str, &lan_addr->ext_ip_addr)) {				/* error */				fprintf(stderr, "Error parsing address : %s\n", lan_addr->ext_ip_str);			}		}	}#endif	return 0;}/* init phase : * 1) read configuration file * 2) read command line arguments * 3) daemonize * 4) open syslog * 5) check and write pid file * 6) set startup time stamp * 7) compute presentation URL * 8) set signal handlers */static intinit(int argc, char * * argv, struct runtime_vars * v){	int i;	int pid;	int debug_flag = 0;	int options_flag = 0;	int openlog_option;	struct sigaction sa;	/*const char * logfilename = 0;*/	const char * presurl = 0;	const char * optionsfile = "/etc/miniupnpd.conf";	/* first check if "-f" option is used */	for(i=2; i<argc; i++)	{		if(0 == strcmp(argv[i-1], "-f"))		{			optionsfile = argv[i];			options_flag = 1;			break;		}	}	/* set initial values */	SETFLAG(ENABLEUPNPMASK);	/*v->n_lan_addr = 0;*/	v->port = -1;	v->notify_interval = 30;	/* seconds between SSDP announces */	v->clean_ruleset_threshold = 20;	v->clean_ruleset_interval = 0;	/* interval between ruleset check. 0=disabled */	/* read options file first since	 * command line arguments have final say */	if(readoptionsfile(optionsfile) < 0)	{		/* only error if file exists or using -f */		if(access(optionsfile, F_OK) == 0 || options_flag)			fprintf(stderr, "Error reading configuration file %s\n", optionsfile);	}	else	{		for(i=0; i<num_options; i++)		{			switch(ary_options[i].id)			{			case UPNPEXT_IFNAME:				ext_if_name = ary_options[i].value;				break;			case UPNPEXT_IP:				use_ext_ip_addr = ary_options[i].value;				break;			case UPNPLISTENING_IP:				if(n_lan_addr < MAX_LAN_ADDR)/* if(v->n_lan_addr < MAX_LAN_ADDR)*/				{					/*if(parselanaddr(&v->lan_addr[v->n_lan_addr],*/					if(parselanaddr(&lan_addr[n_lan_addr],					             ary_options[i].value) == 0)						n_lan_addr++; /*v->n_lan_addr++; */				}				else				{					fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n",			    		    MAX_LAN_ADDR, ary_options[i].value);				}				break;			case UPNPPORT:				v->port = atoi(ary_options[i].value);				break;			case UPNPBITRATE_UP:				upstream_bitrate = strtoul(ary_options[i].value, 0, 0);				break;			case UPNPBITRATE_DOWN:				downstream_bitrate = strtoul(ary_options[i].value, 0, 0);				break;			case UPNPPRESENTATIONURL:				presurl = ary_options[i].value;				break;			case UPNPNOTIFY_INTERVAL:				v->notify_interval = atoi(ary_options[i].value);				break;			case UPNPSYSTEM_UPTIME:				if(strcmp(ary_options[i].value, "yes") == 0)					SETFLAG(SYSUPTIMEMASK);	/*sysuptime = 1;*/				break;			case UPNPPACKET_LOG:				if(strcmp(ary_options[i].value, "yes") == 0)					SETFLAG(LOGPACKETSMASK);	/*logpackets = 1;*/				break;			case UPNPUUID:				strncpy(uuidvalue+5, ary_options[i].value,				        strlen(uuidvalue+5) + 1);				break;			case UPNPSERIAL:				strncpy(serialnumber, ary_options[i].value, SERIALNUMBER_MAX_LEN);				serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0';				break;							case UPNPMODEL_NUMBER:				strncpy(modelnumber, ary_options[i].value, MODELNUMBER_MAX_LEN);				modelnumber[MODELNUMBER_MAX_LEN-1] = '\0';				break;			case UPNPCLEANTHRESHOLD:				v->clean_ruleset_threshold = atoi(ary_options[i].value);				break;			case UPNPCLEANINTERVAL:				v->clean_ruleset_interval = atoi(ary_options[i].value);				break;#ifdef USE_PF			case UPNPQUEUE:				queue = ary_options[i].value;				break;			case UPNPTAG:				tag = ary_options[i].value;				break;#endif#ifdef ENABLE_NATPMP			case UPNPENABLENATPMP:				if(strcmp(ary_options[i].value, "yes") == 0)					SETFLAG(ENABLENATPMPMASK);	/*enablenatpmp = 1;*/				else					if(atoi(ary_options[i].value))						SETFLAG(ENABLENATPMPMASK);					/*enablenatpmp = atoi(ary_options[i].value);*/				break;#endif#ifdef PF_ENABLE_FILTER_RULES			case UPNPQUICKRULES:				if(strcmp(ary_options[i].value, "no") == 0)					SETFLAG(PFNOQUICKRULESMASK);				break;#endif			case UPNPENABLE:				if(strcmp(ary_options[i].value, "yes") != 0)					CLEARFLAG(ENABLEUPNPMASK);				break;			case UPNPSECUREMODE:				if(strcmp(ary_options[i].value, "yes") == 0)					SETFLAG(SECUREMODEMASK);				break;#ifdef ENABLE_LEASEFILE			case UPNPLEASEFILE:				lease_file = ary_options[i].value;				remove(lease_file);				break;#endif			default:				fprintf(stderr, "Unknown option in file %s\n",				        optionsfile);			}		}	}	/* command line arguments processing */	for(i=1; i<argc; i++)	{		if(argv[i][0]!='-')		{			fprintf(stderr, "Unknown option: %s\n", argv[i]);		}		else switch(argv[i][1])		{		case 'o':			if(i+1 < argc)				use_ext_ip_addr = argv[++i];			else				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);			break;		case 't':			if(i+1 < argc)				v->notify_interval = atoi(argv[++i]);			else				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);			break;		case 'u':			if(i+1 < argc)				strncpy(uuidvalue+5, argv[++i], strlen(uuidvalue+5) + 1);			else				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);			break;		case 's':			if(i+1 < argc)				strncpy(serialnumber, argv[++i], SERIALNUMBER_MAX_LEN);			else				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);			serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0';			break;		case 'm':			if(i+1 < argc)				strncpy(modelnumber, argv[++i], MODELNUMBER_MAX_LEN);			else				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);			modelnumber[MODELNUMBER_MAX_LEN-1] = '\0';			break;#ifdef ENABLE_NATPMP		case 'N':			/*enablenatpmp = 1;*/			SETFLAG(ENABLENATPMPMASK);			break;#endif		case 'U':			/*sysuptime = 1;*/			SETFLAG(SYSUPTIMEMASK);			break;		/*case 'l':			logfilename = argv[++i];			break;*/		case 'L':			/*logpackets = 1;*/			SETFLAG(LOGPACKETSMASK);			break;		case 'S':			SETFLAG(SECUREMODEMASK);			break;		case 'i':			if(i+1 < argc)				ext_if_name = argv[++i];			else				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);			break;#ifdef USE_PF		case 'q':			if(i+1 < argc)				queue = argv[++i];			else				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);			break;		case 'T':			if(i+1 < argc)				tag = argv[++i];			else				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);			break;#endif		case 'p':			if(i+1 < argc)				v->port = atoi(argv[++i]);			else				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);			break;		case 'P':			if(i+1 < argc)				pidfilename = argv[++i];			else				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);			break;		case 'd':			debug_flag = 1;			break;		case 'w':			if(i+1 < argc)				presurl = argv[++i];			else				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -