1/* $Id: natpmp.c,v 1.52 2015/05/27 12:43:14 nanard Exp $ */
2/* MiniUPnP project
3 * (c) 2007-2015 Thomas Bernard
4 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
5 * This software is subject to the conditions detailed
6 * in the LICENCE file provided within the distribution */
7#include <stdio.h>
8#include <string.h>
9#include <unistd.h>
10#include <syslog.h>
11#include <errno.h>
12#include <time.h>
13#include <sys/types.h>
14#include <sys/socket.h>
15#include <netinet/in.h>
16#include <arpa/inet.h>
17#include <sys/uio.h>
18
19#include "macros.h"
20#include "config.h"
21#include "natpmp.h"
22#include "upnpglobalvars.h"
23#include "getifaddr.h"
24#include "upnpredirect.h"
25#include "commonrdr.h"
26#include "upnputils.h"
27#include "portinuse.h"
28#include "asyncsendto.h"
29
30#ifdef ENABLE_NATPMP
31
32#define INLINE static inline
33/* theses macros are designed to read/write unsigned short/long int
34 * from an unsigned char array in network order (big endian).
35 * Avoid pointer casting, so avoid accessing unaligned memory, which
36 * can crash with some cpu's */
37INLINE uint32_t readnu32(const uint8_t * p)
38{
39	return (p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]);
40}
41#define READNU32(p) readnu32(p)
42INLINE uint16_t readnu16(const uint8_t * p)
43{
44	return (p[0] << 8 | p[1]);
45}
46#define READNU16(p) readnu16(p)
47INLINE void writenu32(uint8_t * p, uint32_t n)
48{
49	p[0] = (n & 0xff000000) >> 24;
50	p[1] = (n & 0xff0000) >> 16;
51	p[2] = (n & 0xff00) >> 8;
52	p[3] = n & 0xff;
53}
54#define WRITENU32(p, n) writenu32(p, n)
55INLINE void writenu16(uint8_t * p, uint16_t n)
56{
57	p[0] = (n & 0xff00) >> 8;
58	p[1] = n & 0xff;
59}
60#define WRITENU16(p, n) writenu16(p, n)
61
62int OpenAndConfNATPMPSocket(in_addr_t addr)
63{
64	int snatpmp;
65	int i = 1;
66	snatpmp = socket(PF_INET, SOCK_DGRAM, 0/*IPPROTO_UDP*/);
67	if(snatpmp<0)
68	{
69		syslog(LOG_ERR, "%s: socket(): %m",
70		       "OpenAndConfNATPMPSocket");
71		return -1;
72	}
73	if(setsockopt(snatpmp, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0)
74	{
75		syslog(LOG_WARNING, "%s: setsockopt(SO_REUSEADDR): %m",
76		       "OpenAndConfNATPMPSocket");
77	}
78	if(!set_non_blocking(snatpmp))
79	{
80		syslog(LOG_WARNING, "%s: set_non_blocking(): %m",
81		       "OpenAndConfNATPMPSocket");
82	}
83	{
84		struct sockaddr_in natpmp_addr;
85		memset(&natpmp_addr, 0, sizeof(natpmp_addr));
86		natpmp_addr.sin_family = AF_INET;
87		natpmp_addr.sin_port = htons(NATPMP_PORT);
88		/*natpmp_addr.sin_addr.s_addr = INADDR_ANY; */
89		natpmp_addr.sin_addr.s_addr = addr;
90		if(bind(snatpmp, (struct sockaddr *)&natpmp_addr, sizeof(natpmp_addr)) < 0)
91		{
92			syslog(LOG_ERR, "%s: bind(): %m",
93			       "OpenAndConfNATPMPSocket");
94			close(snatpmp);
95			return -1;
96		}
97	}
98	return snatpmp;
99}
100
101int OpenAndConfNATPMPSockets(int * sockets)
102{
103	int i;
104	struct lan_addr_s * lan_addr;
105	for(i = 0, lan_addr = lan_addrs.lh_first;
106	    lan_addr != NULL;
107	    lan_addr = lan_addr->list.le_next)
108	{
109		sockets[i] = OpenAndConfNATPMPSocket(lan_addr->addr.s_addr);
110		if(sockets[i] < 0)
111			goto error;
112		i++;
113	}
114	return 0;
115error:
116	while(--i >= 0)
117	{
118		close(sockets[i]);
119		sockets[i] = -1;
120	}
121	return -1;
122}
123
124static void FillPublicAddressResponse(unsigned char * resp, in_addr_t senderaddr)
125{
126#ifndef MULTIPLE_EXTERNAL_IP
127	char tmp[16];
128	UNUSED(senderaddr);
129
130	if(use_ext_ip_addr) {
131        inet_pton(AF_INET, use_ext_ip_addr, resp+8);
132	} else {
133		if(!ext_if_name || ext_if_name[0]=='\0') {
134			resp[3] = 3;	/* Network Failure (e.g. NAT box itself
135			                 * has not obtained a DHCP lease) */
136		} else if(getifaddr(ext_if_name, tmp, INET_ADDRSTRLEN, NULL, NULL) < 0) {
137			syslog(LOG_ERR, "Failed to get IP for interface %s", ext_if_name);
138			resp[3] = 3;	/* Network Failure (e.g. NAT box itself
139			                 * has not obtained a DHCP lease) */
140		} else {
141			inet_pton(AF_INET, tmp, resp+8); /* ok */
142		}
143	}
144#else
145	struct lan_addr_s * lan_addr;
146
147	for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next) {
148		if( (senderaddr & lan_addr->mask.s_addr)
149		   == (lan_addr->addr.s_addr & lan_addr->mask.s_addr)) {
150			memcpy(resp+8, &lan_addr->ext_ip_addr,
151			       sizeof(lan_addr->ext_ip_addr));
152			break;
153		}
154	}
155#endif
156}
157
158/*
159 * Receives NATPMP and PCP packets and stores them in msg_buff.
160 * The sender information is stored in senderaddr.
161 * Returns number of bytes recevied, even if number is negative.
162 */
163int ReceiveNATPMPOrPCPPacket(int s, struct sockaddr * senderaddr,
164                             socklen_t * senderaddrlen,
165                             struct sockaddr_in6 * receiveraddr,
166                             unsigned char * msg_buff, size_t msg_buff_size)
167{
168#ifdef IPV6_PKTINFO
169	struct iovec iov;
170	uint8_t c[1000];
171	struct msghdr msg;
172	int n;
173	struct cmsghdr *h;
174
175	iov.iov_base = msg_buff;
176	iov.iov_len = msg_buff_size;
177	memset(&msg, 0, sizeof(msg));
178	msg.msg_iov = &iov;
179	msg.msg_iovlen = 1;
180	msg.msg_name = senderaddr;
181	msg.msg_namelen = *senderaddrlen;
182	msg.msg_control = c;
183	msg.msg_controllen = sizeof(c);
184
185	n = recvmsg(s, &msg, 0);
186	if(n < 0) {
187		/* EAGAIN, EWOULDBLOCK and EINTR : silently ignore (retry next time)
188		 * other errors : log to LOG_ERR */
189		if(errno != EAGAIN &&
190		   errno != EWOULDBLOCK &&
191		   errno != EINTR) {
192			syslog(LOG_ERR, "recvmsg(natpmp): %m");
193		}
194		return n;
195	}
196
197	if(receiveraddr) {
198		memset(receiveraddr, 0, sizeof(struct sockaddr_in6));
199	}
200	if ((msg.msg_flags & MSG_TRUNC) || (msg.msg_flags & MSG_CTRUNC)) {
201		syslog(LOG_WARNING, "%s: truncated message",
202		       "ReceiveNATPMPOrPCPPacket");
203	}
204	for(h = CMSG_FIRSTHDR(&msg); h;
205	    h = CMSG_NXTHDR(&msg, h)) {
206		if(h->cmsg_level == IPPROTO_IPV6 && h->cmsg_type == IPV6_PKTINFO) {
207			char tmp[INET6_ADDRSTRLEN];
208			struct in6_pktinfo *ipi6 = (struct in6_pktinfo *)CMSG_DATA(h);
209			syslog(LOG_DEBUG, "%s: packet destination: %s scope_id=%u",
210			       "ReceiveNATPMPOrPCPPacket",
211			       inet_ntop(AF_INET6, &ipi6->ipi6_addr, tmp, sizeof(tmp)),
212			       ipi6->ipi6_ifindex);
213			if(receiveraddr) {
214				receiveraddr->sin6_addr = ipi6->ipi6_addr;
215				receiveraddr->sin6_scope_id = ipi6->ipi6_ifindex;
216				receiveraddr->sin6_family = AF_INET6;
217				receiveraddr->sin6_port = htons(NATPMP_PORT);
218			}
219		}
220	}
221#else /* IPV6_PKTINFO */
222	int n;
223
224	n = recvfrom(s, msg_buff, msg_buff_size, 0,
225	             senderaddr, senderaddrlen);
226
227	if(n<0) {
228		/* EAGAIN, EWOULDBLOCK and EINTR : silently ignore (retry next time)
229		 * other errors : log to LOG_ERR */
230		if(errno != EAGAIN &&
231		   errno != EWOULDBLOCK &&
232		   errno != EINTR) {
233			syslog(LOG_ERR, "recvfrom(natpmp): %m");
234		}
235		return n;
236	}
237#endif /* IPV6_PKTINFO */
238
239	return n;
240}
241
242/** read the request from the socket, process it and then send the
243 * response back.
244 */
245void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len,
246		struct sockaddr_in *senderaddr)
247{
248	unsigned char *req=msg_buff;	/* request udp packet */
249	unsigned char resp[32];	/* response udp packet */
250	int resplen;
251	int n = len;
252	char senderaddrstr[16];
253
254	if(!inet_ntop(AF_INET, &senderaddr->sin_addr,
255			senderaddrstr, sizeof(senderaddrstr))) {
256		syslog(LOG_ERR, "inet_ntop(natpmp): %m");
257	}
258
259	syslog(LOG_INFO, "NAT-PMP request received from %s:%hu %dbytes",
260	       senderaddrstr, ntohs(senderaddr->sin_port), n);
261
262	if(n<2 || ((((req[1]-1)&~1)==0) && n<12)) {
263		syslog(LOG_WARNING, "discarding NAT-PMP request (too short) %dBytes",
264		       n);
265		return;
266	}
267	if(req[1] & 128) {
268		/* discarding NAT-PMP responses silently */
269		return;
270	}
271	memset(resp, 0, sizeof(resp));
272	resplen = 8;
273	resp[1] = 128 + req[1];	/* response OPCODE is request OPCODE + 128 */
274	/* setting response TIME STAMP :
275	 * time elapsed since its port mapping table was initialized on
276	 * startup or reset for any other reason */
277	WRITENU32(resp+4, time(NULL) - startup_time);
278	if(req[0] > 0) {
279		/* invalid version */
280		syslog(LOG_WARNING, "unsupported NAT-PMP version : %u",
281		       (unsigned)req[0]);
282		resp[3] = 1;	/* unsupported version */
283	} else switch(req[1]) {
284	case 0:	/* Public address request */
285		syslog(LOG_INFO, "NAT-PMP public address request");
286		FillPublicAddressResponse(resp, senderaddr->sin_addr.s_addr);
287		resplen = 12;
288		break;
289	case 1:	/* UDP port mapping request */
290	case 2:	/* TCP port mapping request */
291		{
292			unsigned short iport;	/* private port */
293			unsigned short eport;	/* public port */
294			uint32_t lifetime; 		/* lifetime=0 => remove port mapping */
295			int r;
296			int proto;
297			char iaddr_old[16];
298			unsigned short iport_old;
299			unsigned int timestamp;
300
301			iport = READNU16(req+4);
302			eport = READNU16(req+6);
303			lifetime = READNU32(req+8);
304			proto = (req[1]==1)?IPPROTO_UDP:IPPROTO_TCP;
305			syslog(LOG_INFO, "NAT-PMP port mapping request : "
306			                 "%hu->%s:%hu %s lifetime=%us",
307			                 eport, senderaddrstr, iport,
308			                 (req[1]==1)?"udp":"tcp", lifetime);
309			/* TODO: accept port mapping if iport ok but eport not ok
310			 * (and set eport correctly) */
311			if(lifetime == 0) {
312				/* remove the mapping */
313				/* RFC6886 :
314				 * A client MAY also send an explicit packet to request deletion of a
315				 * mapping that is no longer needed. A client requests explicit
316				 * deletion of a mapping by sending a message to the NAT gateway
317				 * requesting the mapping, with the Requested Lifetime in Seconds set to
318				 * zero. The Suggested External Port MUST be set to zero by the client
319				 * on sending, and MUST be ignored by the gateway on reception. */
320				int index = 0;
321				unsigned short eport2, iport2;
322				char iaddr2[16];
323				int proto2;
324				char desc[64];
325				eport = 0; /* to indicate correct removing of port mapping */
326				while(get_redirect_rule_by_index(index, 0,
327				          &eport2, iaddr2, sizeof(iaddr2),
328						  &iport2, &proto2,
329						  desc, sizeof(desc),
330				          0, 0, &timestamp, 0, 0) >= 0) {
331					syslog(LOG_DEBUG, "%d %d %hu->'%s':%hu '%s'",
332					       index, proto2, eport2, iaddr2, iport2, desc);
333					if(0 == strcmp(iaddr2, senderaddrstr)
334					  && 0 == memcmp(desc, "NAT-PMP", 7)) {
335						/* (iport == 0) => remove all the mappings for this client */
336						if((iport == 0) || ((iport == iport2) && (proto == proto2))) {
337							r = _upnp_delete_redir(eport2, proto2);
338							if(r < 0) {
339								syslog(LOG_ERR, "Failed to remove NAT-PMP mapping eport %hu, protocol %s",
340								       eport2, (proto2==IPPROTO_TCP)?"TCP":"UDP");
341								resp[3] = 2;	/* Not Authorized/Refused */
342								break;
343							} else {
344								syslog(LOG_DEBUG, "NAT-PMP %s port %hu mapping removed",
345								       proto2==IPPROTO_TCP?"TCP":"UDP", eport2);
346								index--;
347							}
348						}
349					}
350					index++;
351				}
352			} else if(iport==0) {
353				resp[3] = 2;	/* Not Authorized/Refused */
354			} else { /* iport > 0 && lifetime > 0 */
355				unsigned short eport_first = 0;
356				int any_eport_allowed = 0;
357				char desc[64];
358				if(eport==0)	/* if no suggested external port, use same a internal port */
359					eport = iport;
360				while(resp[3] == 0) {
361					if(eport_first == 0) { /* first time in loop */
362						eport_first = eport;
363					} else if(eport == eport_first) { /* no eport available */
364						if(any_eport_allowed == 0) { /* all eports rejected by permissions */
365							syslog(LOG_ERR, "No allowed eport for NAT-PMP %hu %s->%s:%hu",
366							       eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport);
367							resp[3] = 2;	/* Not Authorized/Refused */
368						} else { /* at least one eport allowed (but none available) */
369							syslog(LOG_ERR, "Failed to find available eport for NAT-PMP %hu %s->%s:%hu",
370							       eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport);
371							resp[3] = 4;	/* Out of resources */
372						}
373						break;
374					}
375					if(!check_upnp_rule_against_permissions(upnppermlist, num_upnpperm, eport, senderaddr->sin_addr, iport)) {
376						eport++;
377						if(eport == 0) eport++; /* skip port zero */
378						continue;
379					}
380					any_eport_allowed = 1;	/* at lease one eport is allowed */
381#ifdef CHECK_PORTINUSE
382					if (port_in_use(ext_if_name, eport, proto, senderaddrstr, iport) > 0) {
383						syslog(LOG_INFO, "port %hu protocol %s already in use",
384						       eport, (proto==IPPROTO_TCP)?"tcp":"udp");
385						eport++;
386						if(eport == 0) eport++; /* skip port zero */
387						continue;
388					}
389#endif
390					r = get_redirect_rule(ext_if_name, eport, proto,
391					                      iaddr_old, sizeof(iaddr_old),
392					                      &iport_old, 0, 0, 0, 0,
393					                      &timestamp, 0, 0);
394					if(r==0) {
395						if(strcmp(senderaddrstr, iaddr_old)==0
396						    && iport==iport_old) {
397							/* redirection already existing */
398							syslog(LOG_INFO, "port %hu %s already redirected to %s:%hu, replacing",
399							       eport, (proto==IPPROTO_TCP)?"tcp":"udp", iaddr_old, iport_old);
400							/* remove and then add again */
401							if(_upnp_delete_redir(eport, proto) < 0) {
402								syslog(LOG_ERR, "failed to remove port mapping");
403								break;
404							}
405						} else {
406							eport++;
407							if(eport == 0) eport++; /* skip port zero */
408							continue;
409						}
410					}
411					/* do the redirection */
412#if 0
413					timestamp = (unsigned)(time(NULL) - startup_time)
414					                      + lifetime;
415					snprintf(desc, sizeof(desc), "NAT-PMP %u", timestamp);
416#else
417					timestamp = time(NULL) + lifetime;
418					snprintf(desc, sizeof(desc), "NAT-PMP %hu %s",
419					         eport, (proto==IPPROTO_TCP)?"tcp":"udp");
420#endif
421					/* TODO : check return code */
422					if(upnp_redirect_internal(NULL, eport, senderaddrstr,
423					                          iport, proto, desc,
424					                          timestamp) < 0) {
425						syslog(LOG_ERR, "Failed to add NAT-PMP %hu %s->%s:%hu '%s'",
426						       eport, (proto==IPPROTO_TCP)?"tcp":"udp", senderaddrstr, iport, desc);
427						resp[3] = 3;  /* Failure */
428					}
429					break;
430				}
431			}
432			WRITENU16(resp+8, iport);	/* private port */
433			WRITENU16(resp+10, eport);	/* public port */
434			WRITENU32(resp+12, lifetime);	/* Port Mapping lifetime */
435		}
436		resplen = 16;
437		break;
438	default:
439		resp[3] = 5;	/* Unsupported OPCODE */
440	}
441	n = sendto_or_schedule(s, resp, resplen, 0,
442	           (struct sockaddr *)senderaddr, sizeof(*senderaddr));
443	if(n<0) {
444		syslog(LOG_ERR, "sendto(natpmp): %m");
445	} else if(n<resplen) {
446		syslog(LOG_ERR, "sendto(natpmp): sent only %d bytes out of %d",
447		       n, resplen);
448	}
449}
450
451/* SendNATPMPPublicAddressChangeNotification()
452 * should be called when the public IP address changed */
453void SendNATPMPPublicAddressChangeNotification(int * sockets, int n_sockets)
454{
455	struct sockaddr_in sockname;
456	unsigned char notif[12];
457	int j, n;
458
459	notif[0] = 0;	/* vers */
460	notif[1] = 128;	/* OP code */
461	notif[2] = 0;	/* result code */
462	notif[3] = 0;	/* result code */
463	/* seconds since "start of epoch" :
464	 * time elapsed since the port mapping table was initialized on
465	 * startup or reset for any other reason */
466	WRITENU32(notif+4, time(NULL) - startup_time);
467#ifndef MULTIPLE_EXTERNAL_IP
468	FillPublicAddressResponse(notif, 0);
469	if(notif[3])
470	{
471		syslog(LOG_WARNING, "%s: cannot get public IP address, stopping",
472		       "SendNATPMPPublicAddressChangeNotification");
473		return;
474	}
475#endif
476	memset(&sockname, 0, sizeof(struct sockaddr_in));
477    sockname.sin_family = AF_INET;
478    sockname.sin_addr.s_addr = inet_addr(NATPMP_NOTIF_ADDR);
479
480	for(j=0; j<n_sockets; j++)
481	{
482		if(sockets[j] < 0)
483			continue;
484#ifdef MULTIPLE_EXTERNAL_IP
485		{
486			struct lan_addr_s * lan_addr = lan_addrs.lh_first;
487			int i;
488			for(i=0; i<j; i++)
489				lan_addr = lan_addr->list.le_next;
490			FillPublicAddressResponse(notif, lan_addr->addr.s_addr);
491		}
492#endif
493		/* Port to use in 2006 version of the NAT-PMP specification */
494    	sockname.sin_port = htons(NATPMP_PORT);
495		n = sendto_or_schedule(sockets[j], notif, 12, 0,
496		           (struct sockaddr *)&sockname, sizeof(struct sockaddr_in));
497		if(n < 0)
498		{
499			syslog(LOG_ERR, "%s: sendto(s_udp=%d): %m",
500			       "SendNATPMPPublicAddressChangeNotification", sockets[j]);
501			return;
502		}
503		/* Port to use in 2008 version of the NAT-PMP specification */
504    	sockname.sin_port = htons(NATPMP_NOTIF_PORT);
505		n = sendto_or_schedule(sockets[j], notif, 12, 0,
506		           (struct sockaddr *)&sockname, sizeof(struct sockaddr_in));
507		if(n < 0)
508		{
509			syslog(LOG_ERR, "%s: sendto(s_udp=%d): %m",
510			       "SendNATPMPPublicAddressChangeNotification", sockets[j]);
511			return;
512		}
513	}
514}
515
516#endif
517
518