1 /* $Id: natpmp.c,v 1.51 2015/02/08 09:18:15 nanard Exp $ */
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 */
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <netinet/in.h>
16 #include <arpa/inet.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"
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;
54 #define WRITENU32(p, n) writenu32(p, n)
55 INLINE
void writenu16(uint8_t * p
, uint16_t n
)
57 p
[0] = (n
& 0xff00) >> 8;
60 #define WRITENU16(p, n) writenu16(p, n)
62 int OpenAndConfNATPMPSocket(in_addr_t addr
)
66 snatpmp
= socket(PF_INET
, SOCK_DGRAM
, 0/*IPPROTO_UDP*/);
69 syslog(LOG_ERR
, "%s: socket(): %m",
70 "OpenAndConfNATPMPSocket");
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");
101 int OpenAndConfNATPMPSockets(int * sockets
)
104 struct lan_addr_s
* lan_addr
;
105 for(i
= 0, lan_addr
= lan_addrs
.lh_first
;
107 lan_addr
= lan_addr
->list
.le_next
)
109 sockets
[i
] = OpenAndConfNATPMPSocket(lan_addr
->addr
.s_addr
);
124 static void FillPublicAddressResponse(unsigned char * resp
, in_addr_t senderaddr
)
126 #ifndef MULTIPLE_EXTERNAL_IP
130 if(use_ext_ip_addr
) {
131 inet_pton(AF_INET
, use_ext_ip_addr
, resp
+8);
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) */
141 inet_pton(AF_INET
, tmp
, resp
+8); /* ok */
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
));
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
)
175 iov
.iov_base
= msg_buff
;
176 iov
.iov_len
= msg_buff_size
;
177 memset(&msg
, 0, sizeof(msg
));
180 msg
.msg_name
= senderaddr
;
181 msg
.msg_namelen
= *senderaddrlen
;
183 msg
.msg_controllen
= sizeof(c
);
185 n
= recvmsg(s
, &msg
, 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
&&
192 syslog(LOG_ERR
, "recvmsg(natpmp): %m");
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
)),
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 */
224 n
= recvfrom(s
, msg_buff
, msg_buff_size
, 0,
225 senderaddr
, senderaddrlen
);
228 /* EAGAIN, EWOULDBLOCK and EINTR : silently ignore (retry next time)
229 * other errors : log to LOG_ERR */
230 if(errno
!= EAGAIN
&&
231 errno
!= EWOULDBLOCK
&&
233 syslog(LOG_ERR
, "recvfrom(natpmp): %m");
237 #endif /* IPV6_PKTINFO */
242 /** read the request from the socket, process it and then send the
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 */
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",
268 /* discarding NAT-PMP responses silently */
271 memset(resp
, 0, sizeof(resp
));
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
);
279 /* invalid version */
280 syslog(LOG_WARNING
, "unsupported NAT-PMP version : %u",
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
);
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 */
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) */
312 /* remove the mapping */
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. */
321 unsigned short eport2
, iport2
;
325 eport
= 0; /* to indicate correct removing of port mapping */
326 while(get_redirect_rule_by_index(index
, 0,
327 &eport2
, iaddr2
, sizeof(iaddr2
),
330 0, 0, ×tamp
, 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
);
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 */
344 syslog(LOG_INFO
, "NAT-PMP %s port %hu mapping removed",
345 proto2
==IPPROTO_TCP
?"TCP":"UDP", eport2
);
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;
358 if(eport
==0) /* if no suggested external port, use same a internal port */
360 while(resp
[3] == 0) {
361 if(eport_first
== 0) { /* first time in loop */
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 */
375 if(!check_upnp_rule_against_permissions(upnppermlist
, num_upnpperm
, eport
, senderaddr
->sin_addr
, iport
)) {
377 if(eport
== 0) eport
++; /* skip port zero */
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");
386 if(eport
== 0) eport
++; /* skip port zero */
390 r
= get_redirect_rule(ext_if_name
, eport
, proto
,
391 iaddr_old
, sizeof(iaddr_old
),
392 &iport_old
, 0, 0, 0, 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");
407 if(eport
== 0) eport
++; /* skip port zero */
411 /* do the redirection */
413 timestamp
= (unsigned)(time(NULL
) - startup_time
)
415 snprintf(desc
, sizeof(desc
), "NAT-PMP %u", timestamp
);
417 timestamp
= time(NULL
) + lifetime
;
418 snprintf(desc
, sizeof(desc
), "NAT-PMP %hu %s",
419 eport
, (proto
==IPPROTO_TCP
)?"tcp":"udp");
421 /* TODO : check return code */
422 if(upnp_redirect_internal(NULL
, eport
, senderaddrstr
,
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 */
432 WRITENU16(resp
+8, iport
); /* private port */
433 WRITENU16(resp
+10, eport
); /* public port */
434 WRITENU32(resp
+12, lifetime
); /* Port Mapping lifetime */
439 resp
[3] = 5; /* Unsupported OPCODE */
441 n
= sendto_or_schedule(s
, resp
, resplen
, 0,
442 (struct sockaddr
*)senderaddr
, sizeof(*senderaddr
));
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",
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];
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);
471 syslog(LOG_WARNING
, "%s: cannot get public IP address, stopping",
472 "SendNATPMPPublicAddressChangeNotification");
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
++)
484 #ifdef MULTIPLE_EXTERNAL_IP
486 struct lan_addr_s
* lan_addr
= lan_addrs
.lh_first
;
489 lan_addr
= lan_addr
->list
.le_next
;
490 FillPublicAddressResponse(notif
, lan_addr
->addr
.s_addr
);
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
));
499 syslog(LOG_ERR
, "%s: sendto(s_udp=%d): %m",
500 "SendNATPMPPublicAddressChangeNotification", sockets
[j
]);
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
));
509 syslog(LOG_ERR
, "%s: sendto(s_udp=%d): %m",
510 "SendNATPMPPublicAddressChangeNotification", sockets
[j
]);