Miniupnpd: update to 1.9 (20150430)
[tomato.git] / release / src / router / miniupnpd / natpmp.c
blob455748e43de0c2dd5bd38bc3e080ee61ef394c81
1 /* $Id: natpmp.c,v 1.51 2015/02/08 09:18:15 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>
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"
30 #ifdef ENABLE_NATPMP
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 */
37 INLINE uint32_t readnu32(const uint8_t * p)
39 return (p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]);
41 #define READNU32(p) readnu32(p)
42 INLINE uint16_t readnu16(const uint8_t * p)
44 return (p[0] << 8 | p[1]);
46 #define READNU16(p) readnu16(p)
47 INLINE void writenu32(uint8_t * p, uint32_t n)
49 p[0] = (n & 0xff000000) >> 24;
50 p[1] = (n & 0xff0000) >> 16;
51 p[2] = (n & 0xff00) >> 8;
52 p[3] = n & 0xff;
54 #define WRITENU32(p, n) writenu32(p, n)
55 INLINE void writenu16(uint8_t * p, uint16_t n)
57 p[0] = (n & 0xff00) >> 8;
58 p[1] = n & 0xff;
60 #define WRITENU16(p, n) writenu16(p, n)
62 int OpenAndConfNATPMPSocket(in_addr_t addr)
64 int snatpmp;
65 int i = 1;
66 snatpmp = socket(PF_INET, SOCK_DGRAM, 0/*IPPROTO_UDP*/);
67 if(snatpmp<0)
69 syslog(LOG_ERR, "%s: socket(): %m",
70 "OpenAndConfNATPMPSocket");
71 return -1;
73 if(setsockopt(snatpmp, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0)
75 syslog(LOG_WARNING, "%s: setsockopt(SO_REUSEADDR): %m",
76 "OpenAndConfNATPMPSocket");
78 if(!set_non_blocking(snatpmp))
80 syslog(LOG_WARNING, "%s: set_non_blocking(): %m",
81 "OpenAndConfNATPMPSocket");
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)
92 syslog(LOG_ERR, "%s: bind(): %m",
93 "OpenAndConfNATPMPSocket");
94 close(snatpmp);
95 return -1;
98 return snatpmp;
101 int OpenAndConfNATPMPSockets(int * sockets)
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)
109 sockets[i] = OpenAndConfNATPMPSocket(lan_addr->addr.s_addr);
110 if(sockets[i] < 0)
111 goto error;
112 i++;
114 return 0;
115 error:
116 while(--i >= 0)
118 close(sockets[i]);
119 sockets[i] = -1;
121 return -1;
124 static void FillPublicAddressResponse(unsigned char * resp, in_addr_t senderaddr)
126 #ifndef MULTIPLE_EXTERNAL_IP
127 char tmp[16];
128 UNUSED(senderaddr);
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 */
144 #else
145 struct lan_addr_s * lan_addr;
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;
155 #endif
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.
163 int 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)
168 #ifdef IPV6_PKTINFO
169 struct iovec iov;
170 uint8_t c[1000];
171 struct msghdr msg;
172 int n;
173 struct cmsghdr *h;
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);
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");
194 return n;
197 if(receiveraddr) {
198 memset(receiveraddr, 0, sizeof(struct sockaddr_in6));
200 if ((msg.msg_flags & MSG_TRUNC) || (msg.msg_flags & MSG_CTRUNC)) {
201 syslog(LOG_WARNING, "%s: truncated message",
202 "ReceiveNATPMPOrPCPPacket");
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);
221 #else /* IPV6_PKTINFO */
222 int n;
224 n = recvfrom(s, msg_buff, msg_buff_size, 0,
225 senderaddr, senderaddrlen);
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");
235 return n;
237 #endif /* IPV6_PKTINFO */
239 return n;
242 /** read the request from the socket, process it and then send the
243 * response back.
245 void ProcessIncomingNATPMPPacket(int s, unsigned char *msg_buff, int len,
246 struct sockaddr_in *senderaddr)
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];
254 if(!inet_ntop(AF_INET, &senderaddr->sin_addr,
255 senderaddrstr, sizeof(senderaddrstr))) {
256 syslog(LOG_ERR, "inet_ntop(natpmp): %m");
259 syslog(LOG_INFO, "NAT-PMP request received from %s:%hu %dbytes",
260 senderaddrstr, ntohs(senderaddr->sin_port), n);
262 if(n<2 || ((((req[1]-1)&~1)==0) && n<12)) {
263 syslog(LOG_WARNING, "discarding NAT-PMP request (too short) %dBytes",
265 return;
267 if(req[1] & 128) {
268 /* discarding NAT-PMP responses silently */
269 return;
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 */
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;
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_INFO, "NAT-PMP %s port %hu mapping removed",
345 proto2==IPPROTO_TCP?"TCP":"UDP", eport2);
346 index--;
350 index++;
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 */
373 break;
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;
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;
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 allready 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;
405 } else {
406 eport++;
407 if(eport == 0) eport++; /* skip port zero */
408 continue;
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 */
429 break;
432 WRITENU16(resp+8, iport); /* private port */
433 WRITENU16(resp+10, eport); /* public port */
434 WRITENU32(resp+12, lifetime); /* Port Mapping lifetime */
436 resplen = 16;
437 break;
438 default:
439 resp[3] = 5; /* Unsupported OPCODE */
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);
451 /* SendNATPMPPublicAddressChangeNotification()
452 * should be called when the public IP address changed */
453 void SendNATPMPPublicAddressChangeNotification(int * sockets, int n_sockets)
455 struct sockaddr_in sockname;
456 unsigned char notif[12];
457 int j, n;
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])
471 syslog(LOG_WARNING, "%s: cannot get public IP address, stopping",
472 "SendNATPMPPublicAddressChangeNotification");
473 return;
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);
480 for(j=0; j<n_sockets; j++)
482 if(sockets[j] < 0)
483 continue;
484 #ifdef MULTIPLE_EXTERNAL_IP
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);
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)
499 syslog(LOG_ERR, "%s: sendto(s_udp=%d): %m",
500 "SendNATPMPPublicAddressChangeNotification", sockets[j]);
501 return;
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)
509 syslog(LOG_ERR, "%s: sendto(s_udp=%d): %m",
510 "SendNATPMPPublicAddressChangeNotification", sockets[j]);
511 return;
516 #endif