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, ×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); 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 ×tamp, 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