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