FreeSWITCH API Documentation  1.7.0
switch_nat.c
Go to the documentation of this file.
1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18  *
19  * The Initial Developer of the Original Code is
20  * Anthony Minessale II <anthm@freeswitch.org>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Anthony Minessale II <anthm@freeswitch.org>
27  * Brian K. West <brian@freeswitch.org>
28  * Rupa Schomaker <rupa@rupa.com>
29  *
30  *
31  * switch_nat.c NAT Traversal via NAT-PMP or uPNP
32  *
33  */
34 
35 #include <switch.h>
36 #include "../libs/miniupnpc/miniwget.h"
37 #include "../libs/miniupnpc/miniupnpc.h"
38 #include "../libs/miniupnpc/upnpcommands.h"
39 #include "../libs/miniupnpc/upnperrors.h"
40 #include "../libs/libnatpmp/natpmp.h"
41 
42 #define MULTICAST_BUFFSIZE 65536
43 #define IP_LEN 16
44 #define NAT_REFRESH_INTERVAL 900
45 
46 typedef struct {
48  char nat_type_str[5];
49  struct UPNPUrls urls;
50  struct IGDdatas data;
51  char *descURL;
52  char pub_addr[IP_LEN];
53  char pvt_addr[IP_LEN];
56 
58 
59 typedef struct {
61  int running;
65 
67 
70 
71 static switch_status_t get_upnp_pubaddr(char *pub_addr)
72 {
73  if (UPNP_GetExternalIPAddress(nat_globals.urls.controlURL, nat_globals.data.servicetype, pub_addr) == UPNPCOMMAND_SUCCESS) {
74  if (!strcmp(pub_addr, "0.0.0.0") || zstr_buf(pub_addr)) {
76  "uPNP Device (url: %s) returned an invalid external address of '%s'. Disabling uPNP\n", nat_globals.urls.controlURL,
77  pub_addr);
78  return SWITCH_STATUS_GENERR;
79  }
80  } else {
81  return SWITCH_STATUS_GENERR;
82  }
83  return SWITCH_STATUS_SUCCESS;
84 }
85 
86 static int init_upnp(void)
87 {
88  struct UPNPDev *devlist;
89  struct UPNPDev *dev = NULL;
90  struct UPNPDev *trydev = NULL;
91  char *descXML;
92  int descXMLsize = 0;
93  const char *minissdpdpath = switch_core_get_variable("local_ip_v4");
94 
95  memset(&nat_globals.urls, 0, sizeof(struct UPNPUrls));
96  memset(&nat_globals.data, 0, sizeof(struct IGDdatas));
97 
98  devlist = upnpDiscover(3000, minissdpdpath, minissdpdpath, 0);
99 
100  if (devlist) {
101  dev = devlist;
102  while (dev) {
103  if (strstr(dev->st, "InternetGatewayDevice")) {
104  break;
105  }
106  if (!trydev && !switch_stristr("printer", dev->descURL)) {
107  trydev = dev;
108  }
109 
110  dev = dev->pNext;
111  }
112 
113  }
114 
115  if (!dev && trydev) {
116  dev = trydev; /* defaulting to first device */
117  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "No InternetGatewayDevice, using first entry as default (%s).\n", dev->descURL);
118  } else if (devlist && !dev && !trydev) {
119  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "No InternetGatewayDevice found and I am NOT going to try your printer because printers should not route to the internet, that would be DAFT\n");
120  }
121 
122  if (dev) {
123  descXML = miniwget(dev->descURL, &descXMLsize);
124 
125  nat_globals.descURL = strdup(dev->descURL);
126 
127  if (descXML) {
128  parserootdesc(descXML, descXMLsize, &nat_globals.data);
129  free(descXML);
130  descXML = 0;
131  GetUPNPUrls(&nat_globals.urls, &nat_globals.data, dev->descURL);
132  } else {
133  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Unable to retrieve device description XML (%s).\n", dev->descURL);
134  }
135 
136  freeUPNPDevlist(devlist);
137  }
138 
139  if (get_upnp_pubaddr(nat_globals.pub_addr) == SWITCH_STATUS_SUCCESS) {
140  nat_globals.nat_type = SWITCH_NAT_TYPE_UPNP;
141  return 0;
142  }
143 
144  return -2;
145 }
146 
147 static int get_pmp_pubaddr(char *pub_addr)
148 {
149  int r = 0, i = 0, max = 5;
150  natpmpresp_t response;
151  char *pubaddr = NULL;
152  natpmp_t natpmp;
153  const char *err = NULL;
154  int pflags;
155 
156  if ((r = initnatpmp(&natpmp)) < 0) {
157  err = "init failed";
158  goto end;
159  }
160 
161  if ((r = sendpublicaddressrequest(&natpmp)) < 0) {
162  err = "pub addr req failed";
163  goto end;
164  }
165 
166  do {
167  struct timeval timeout = { 1, 0 };
168 
169  i++;
170  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Checking for PMP %d/%d\n", i, max);
171  if ((r = getnatpmprequesttimeout(&natpmp, &timeout)) < 0) {
172  err = "get timeout failed";
173  goto end;
174  }
175 
177 
178  if ((pflags & SWITCH_POLL_ERROR) || (pflags & SWITCH_POLL_HUP)) {
179  err = "wait sock failed";
180  goto end;
181  }
182  r = readnatpmpresponseorretry(&natpmp, &response);
183  } while (r == NATPMP_TRYAGAIN && i < max);
184 
185  if (r < 0) {
186  err = "general error";
187  goto end;
188  }
189 
190  pubaddr = inet_ntoa(response.pnu.publicaddress.addr);
191  switch_copy_string(pub_addr, pubaddr, IP_LEN);
192  nat_globals.nat_type = SWITCH_NAT_TYPE_PMP;
193 
194  closenatpmp(&natpmp);
195 
196  end:
197 
198  if (err) {
199  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error checking for PMP [%s]\n", err);
200  }
201 
202  return r;
203 }
204 
205 static int init_pmp(void)
206 {
207  return get_pmp_pubaddr(nat_globals.pub_addr);
208 }
209 
211 {
212  nat_globals.mapping = mapping;
213 }
214 
216 {
217  switch_nat_init(nat_globals_perm.pool, nat_globals.mapping);
218 }
219 
221 {
222  char *addr = NULL;
223  switch_port_t port = 0;
224 
225  if (nat_globals.nat_type == SWITCH_NAT_TYPE_UPNP) {
226  addr = "239.255.255.250";
227  port = 1900;
228  } else if (nat_globals.nat_type == SWITCH_NAT_TYPE_PMP) {
229  addr = "224.0.0.1";
230  port = 5350;
231  }
232 
233  if (switch_sockaddr_info_get(&nat_globals_perm.maddress, addr, SWITCH_UNSPEC, port, 0, pool) != SWITCH_STATUS_SUCCESS) {
234  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find address\n");
235  return SWITCH_STATUS_TERM;
236  }
237 
238  if (switch_socket_create(&nat_globals_perm.msocket, AF_INET, SOCK_DGRAM, 0, pool) != SWITCH_STATUS_SUCCESS) {
240  return SWITCH_STATUS_TERM;
241  }
242 
244  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Option Error\n");
245  switch_socket_close(nat_globals_perm.msocket);
246  return SWITCH_STATUS_TERM;
247  }
248 
249  if (switch_mcast_join(nat_globals_perm.msocket, nat_globals_perm.maddress, NULL, NULL) != SWITCH_STATUS_SUCCESS) {
251  switch_socket_close(nat_globals_perm.msocket);
252  return SWITCH_STATUS_TERM;
253  }
254 
255  if (switch_socket_bind(nat_globals_perm.msocket, nat_globals_perm.maddress) != SWITCH_STATUS_SUCCESS) {
257  switch_socket_close(nat_globals_perm.msocket);
258  return SWITCH_STATUS_TERM;
259  }
260 
262  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "NAT thread configured\n");
263  return SWITCH_STATUS_SUCCESS;
264 }
265 
267 {
268  char *buf = NULL;
269  char newip[16] = "";
270  char *pos;
271  switch_event_t *event = NULL;
272 
273  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "NAT thread started\n");
274 
275  buf = (char *) malloc(MULTICAST_BUFFSIZE);
276  switch_assert(buf);
277  nat_globals_perm.running = 1;
278 
279  while (nat_globals_perm.running == 1) {
280  size_t len = MULTICAST_BUFFSIZE;
281  switch_status_t status;
282  switch_bool_t do_repub = SWITCH_FALSE;
283  memset(buf, 0, len);
284 
285  status = switch_socket_recvfrom(nat_globals_perm.maddress, nat_globals_perm.msocket, 0, buf, &len);
286 
287  if (!len) {
288  if (SWITCH_STATUS_IS_BREAK(status)) {
289  switch_yield(5000000);
290  continue;
291  }
292 
293  break;
294  }
295 
296  if (nat_globals.nat_type == SWITCH_NAT_TYPE_UPNP) {
297  /* look for our desc URL and servicetype in the packet */
298  if (strstr(buf, nat_globals.descURL) && (buf == NULL || strstr(buf, nat_globals.data.servicetype))) {
299  if ((pos = strstr(buf, "NTS:"))) {
300  pos = pos + 4;
301  while (*pos && *pos == ' ') {
302  pos++;
303  }
304  if (!strncmp(pos, "ssdp:alive", 10)) {
305  /* switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "got UPnP keep alive packet: \n%s\n", buf); */
306  /* did pub ip change */
307  newip[0] = '\0';
308  if (get_upnp_pubaddr(newip) != SWITCH_STATUS_SUCCESS) {
310  "Unable to get current pubaddr after receiving UPnP keep alive packet.\n");
311  }
312  } else if (!strncmp(pos, "ssdp:byebye", 11)) {
314  "got UPnP signoff packet. Your NAT gateway is probably going offline.\n");
315  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "got UPnP signoff packet: \n%s\n", buf);
316  } else {
317  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "got UNKNOWN UPnP keep alive packet: \n%s\n", buf);
318  }
319  }
320  }
321  } else {
322  /* got some data in NAT-PMP mode, treat any data as a republish event */
323  if (get_pmp_pubaddr(newip) < 0) {
324  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unable to get current pubaddr after receiving UPnP keep alive packet.\n");
325  }
326  }
327 
328  if ((strlen(newip) > 0) && strcmp(newip, "0.0.0.0") && strcmp(newip, nat_globals.pub_addr)) {
329  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Public IP changed from '%s' to '%s'.\n", nat_globals.pub_addr, newip);
330  do_repub = SWITCH_TRUE;
331 
333  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "condition", "network-external-address-change");
334  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "network-external-address-previous-v4", nat_globals.pub_addr);
335  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "network-external-address-change-v4", newip);
336  switch_event_fire(&event);
337 
338  switch_set_string(nat_globals.pub_addr, newip);
340  }
341 
342  if (do_repub) {
344  }
345  }
346 
347  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "NAT thread ending\n");
348  nat_globals_perm.running = 0;
349 
350  switch_safe_free(buf);
351 
352  return NULL;
353 }
354 
356 
358 {
359 
360  switch_threadattr_t *thd_attr;
361 
362  if (init_nat_monitor(nat_globals_perm.pool) != SWITCH_STATUS_SUCCESS) {
363  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to initialize NAT thread\n");
364  return;
365  }
366 
367  switch_threadattr_create(&thd_attr, nat_globals_perm.pool);
368  switch_thread_create(&nat_thread_p, thd_attr, switch_nat_multicast_runtime, NULL, nat_globals_perm.pool);
369 }
370 
372 {
373  /* don't do anything if no thread ptr */
374  if (!nat_thread_p) {
375  return;
376  }
377  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Stopping NAT Task Thread\n");
378  if (nat_globals_perm.running == 1) {
379  int sanity = 0;
380  switch_status_t st;
381 
382  nat_globals_perm.running = -1;
383 
385 
386  while (nat_globals_perm.running) {
387  switch_yield(1000000); /* can take up to 5s for the thread to terminate, so wait for 10 */
388  if (++sanity > 10) {
389  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Timed out waiting for NAT Task Thread to stop\n");
390  break;
391  }
392  }
393  }
394 
395  nat_thread_p = NULL;
396 }
397 
398 
400 {
401  /* try free dynamic data structures prior to resetting to 0 */
402  FreeUPNPUrls(&nat_globals.urls);
403  switch_safe_free(nat_globals.descURL);
404 
405  memset(&nat_globals, 0, sizeof(nat_globals));
406 
407  if (first_init) {
408  memset(&nat_globals_perm, 0, sizeof(nat_globals_perm));
409  nat_globals_perm.pool = pool;
410  }
411 
412  nat_globals.mapping = mapping;
413 
414  switch_find_local_ip(nat_globals.pvt_addr, sizeof(nat_globals.pvt_addr), NULL, AF_INET);
415 
416 
417  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Scanning for NAT\n");
418 
419  init_pmp();
420 
421  if (!nat_globals.nat_type) {
422  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Checking for UPnP\n");
423  init_upnp();
424  }
425 
426  if (nat_globals.nat_type) {
427  switch_core_set_variable("nat_public_addr", nat_globals.pub_addr);
428  switch_core_set_variable("nat_private_addr", nat_globals.pvt_addr);
429  switch_core_set_variable("nat_type", nat_globals.nat_type == SWITCH_NAT_TYPE_PMP ? "pmp" : "upnp");
430  strncpy(nat_globals.nat_type_str, nat_globals.nat_type == SWITCH_NAT_TYPE_PMP ? "pmp" : "upnp", sizeof(nat_globals.nat_type_str) - 1);
431  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "NAT detected type: %s, ExtIP: '%s'\n",
432  nat_globals.nat_type == SWITCH_NAT_TYPE_PMP ? "pmp" : "upnp", nat_globals.pub_addr);
433 
434  if (!nat_thread_p) {
436  }
437  } else {
438  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "No PMP or UPnP NAT devices detected!\n");
439  }
442 }
443 
445 {
447  natpmpresp_t response;
448  int r;
449  natpmp_t natpmp;
450 
451  initnatpmp(&natpmp);
452 
453  if (proto == SWITCH_NAT_TCP) {
454  sendnewportmappingrequest(&natpmp, NATPMP_PROTOCOL_TCP, port, port, 31104000);
455  } else if (proto == SWITCH_NAT_UDP) {
456  sendnewportmappingrequest(&natpmp, NATPMP_PROTOCOL_UDP, port, port, 31104000);
457  }
458 
459  do {
460  fd_set fds;
461  struct timeval timeout = { 1, 0 };
462  FD_ZERO(&fds);
463  FD_SET(natpmp.s, &fds);
464  getnatpmprequesttimeout(&natpmp, &timeout);
465  select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
466  r = readnatpmpresponseorretry(&natpmp, &response);
467  } while (r == NATPMP_TRYAGAIN);
468 
469  if (r == 0) {
470  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "mapped public port %hu protocol %s to localport %hu\n",
471  response.pnu.newportmapping.mappedpublicport,
472  response.type == NATPMP_RESPTYPE_UDPPORTMAPPING ? "UDP" :
473  (response.type == NATPMP_RESPTYPE_TCPPORTMAPPING ? "TCP" : "UNKNOWN"), response.pnu.newportmapping.privateport);
474  if (external_port) {
475  *external_port = response.pnu.newportmapping.mappedpublicport;
476  } else if (response.pnu.newportmapping.mappedpublicport != response.pnu.newportmapping.privateport) {
477  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "External port %hu protocol %s was not available, it was instead mapped to %hu\n",
478  response.pnu.newportmapping.privateport,
479  response.type == NATPMP_RESPTYPE_UDPPORTMAPPING ? "UDP" :
480  (response.type == NATPMP_RESPTYPE_TCPPORTMAPPING ? "TCP" : "UNKNOWN"), response.pnu.newportmapping.mappedpublicport);
481  }
482 
483  status = SWITCH_STATUS_SUCCESS;
484  }
485 
486  closenatpmp(&natpmp);
487 
488  return status;
489 }
490 
492 {
494  char port_str[IP_LEN];
495  int r = UPNPCOMMAND_UNKNOWN_ERROR;
496 
497  sprintf(port_str, "%d", port);
498 
499  if (proto == SWITCH_NAT_TCP) {
500  r = UPNP_AddPortMapping(nat_globals.urls.controlURL, nat_globals.data.servicetype, port_str, port_str,
501  nat_globals.pvt_addr, "FreeSWITCH", "TCP", 0);
502  } else if (proto == SWITCH_NAT_UDP) {
503  r = UPNP_AddPortMapping(nat_globals.urls.controlURL, nat_globals.data.servicetype, port_str, port_str,
504  nat_globals.pvt_addr, "FreeSWITCH", "UDP", 0);
505  }
506 
507  if (r == UPNPCOMMAND_SUCCESS) {
508  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "mapped public port %s protocol %s to localport %s\n", port_str,
509  (proto == SWITCH_NAT_TCP) ? "TCP" : (proto == SWITCH_NAT_UDP ? "UDP" : "UNKNOWN"), port_str);
510  status = SWITCH_STATUS_SUCCESS;
511  }
512 
513  return status;
514 }
515 
517 {
519  natpmpresp_t response;
520  int r;
521  natpmp_t natpmp;
522 
523  initnatpmp(&natpmp);
524 
525  if (proto == SWITCH_NAT_TCP) {
526  sendnewportmappingrequest(&natpmp, NATPMP_PROTOCOL_TCP, port, port, 0);
527  } else if (proto == SWITCH_NAT_UDP) {
528  sendnewportmappingrequest(&natpmp, NATPMP_PROTOCOL_UDP, port, port, 0);
529  }
530 
531  do {
532  fd_set fds;
533  struct timeval timeout;
534  FD_ZERO(&fds);
535  FD_SET(natpmp.s, &fds);
536  getnatpmprequesttimeout(&natpmp, &timeout);
537  select(FD_SETSIZE, &fds, NULL, NULL, &timeout);
538  r = readnatpmpresponseorretry(&natpmp, &response);
539  } while (r == NATPMP_TRYAGAIN);
540 
541  if (r == 0) {
542  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "unmapped public port %hu protocol %s to localport %hu\n", response.pnu.newportmapping.privateport, /* This might be wrong but its so 0 isn't displayed */
543  response.type == NATPMP_RESPTYPE_UDPPORTMAPPING ? "UDP" :
544  (response.type == NATPMP_RESPTYPE_TCPPORTMAPPING ? "TCP" : "UNKNOWN"), response.pnu.newportmapping.privateport);
545  status = SWITCH_STATUS_SUCCESS;
546  }
547 
548  closenatpmp(&natpmp);
549 
550  return status;
551 }
552 
554 {
556  char port_str[IP_LEN];
557  int r = UPNPCOMMAND_UNKNOWN_ERROR;
558 
559  sprintf(port_str, "%d", port);
560 
561  if (proto == SWITCH_NAT_TCP) {
562  r = UPNP_DeletePortMapping(nat_globals.urls.controlURL, nat_globals.data.servicetype, port_str, "TCP", 0);
563  } else if (proto == SWITCH_NAT_UDP) {
564  r = UPNP_DeletePortMapping(nat_globals.urls.controlURL, nat_globals.data.servicetype, port_str, "UDP", 0);
565  }
566 
567  if (r == UPNPCOMMAND_SUCCESS) {
568  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "unmapped public port %s protocol %s to localport %s\n", port_str,
569  (proto == SWITCH_NAT_TCP) ? "TCP" : (proto == SWITCH_NAT_UDP ? "UDP" : "UNKNOWN"), port_str);
570  status = SWITCH_STATUS_SUCCESS;
571  }
572  return status;
573 }
574 
576 {
577  return nat_globals.nat_type_str;
578 }
579 
581  switch_bool_t sticky, switch_bool_t publish)
582 {
584  switch_event_t *event = NULL;
585 
586  if (!initialized || !nat_globals.nat_type) return status;
587  if (!nat_globals.mapping) {
588  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "NAT port mapping disabled\n");
589  return status;
590  }
591 
592  switch (nat_globals.nat_type) {
593  case SWITCH_NAT_TYPE_PMP:
594  status = switch_nat_add_mapping_pmp(port, proto, external_port);
595  break;
597  if ((status = switch_nat_add_mapping_upnp(port, proto)) == SWITCH_STATUS_SUCCESS) {
598  if (external_port) {
599  *external_port = port;
600  }
601  }
602  break;
603  default:
604  break;
605  }
606 
607  if (publish && status == SWITCH_STATUS_SUCCESS) {
610  switch_event_add_header(event, SWITCH_STACK_BOTTOM, "port", "%d", port);
611  switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "%d", proto);
612  switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "sticky", (sticky ? "true" : "false"));
613  switch_event_fire(&event);
614  }
615 
616  return status;
617 }
618 
620  switch_bool_t sticky)
621 {
622  return switch_nat_add_mapping_internal(port, proto, external_port, sticky, SWITCH_TRUE);
623 }
624 
626 {
628  switch_event_t *event = NULL;
629 
630  switch (nat_globals.nat_type) {
631  case SWITCH_NAT_TYPE_PMP:
632  status = switch_nat_del_mapping_pmp(port, proto);
633  break;
635  status = switch_nat_del_mapping_upnp(port, proto);
636  break;
637  default:
638  break;
639  }
640 
641  if (status == SWITCH_STATUS_SUCCESS) {
644  switch_event_add_header(event, SWITCH_STACK_BOTTOM, "port", "%d", port);
645  switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "%d", proto);
646  switch_event_fire(&event);
647  }
648 
649  return status;
650 }
651 
653 {
654  switch_xml_t natxml = NULL;
655  switch_xml_t row = NULL;
656  switch_xml_t child = NULL;
657  switch_stream_handle_t stream = { 0 };
658  SWITCH_STANDARD_STREAM(stream);
659 
660  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Refreshing nat maps\n");
661 
662  switch_api_execute("show", "nat_map as xml", NULL, &stream);
663 
664  if (!(natxml = switch_xml_parse_str_dup(stream.data))) {
665  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to parse XML: %s\n", (char *) stream.data);
666  switch_safe_free(stream.data);
667  return;
668  }
669 
670  /* iterate the xml and publish the mappings */
671  row = switch_xml_find_child(natxml, "row", "row_id", "1");
672  while (row != NULL) {
673  char *sport = NULL;
674  char *sproto = NULL;
675  switch_port_t port;
676  switch_nat_ip_proto_t proto;
677 
678  if ((child = switch_xml_child(row, "port"))) {
679  sport = child->txt;
680  }
681  if ((child = switch_xml_child(row, "proto_num"))) {
682  sproto = child->txt;
683  }
684 
685  if (sport && sproto) {
686  port = (switch_port_t) (atoi(sport));
687  proto = (switch_nat_ip_proto_t) (atoi(sproto));
689  } else {
690  switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to parse port/proto info: XML: %s\n", (char *) stream.data);
691  }
692 
693  row = switch_xml_next(row);
694  }
695 
696  switch_safe_free(stream.data);
697  switch_xml_free(natxml);
698 }
699 
700 SWITCH_STANDARD_SCHED_FUNC(switch_nat_republish_sched)
701 {
703  if (nat_globals_perm.running == 1) {
704  task->runtime = switch_epoch_time_now(NULL) + NAT_REFRESH_INTERVAL;
705  }
706 }
707 
709 {
710  if (nat_globals_perm.running == 1) {
711  switch_scheduler_add_task(switch_epoch_time_now(NULL) + NAT_REFRESH_INTERVAL, switch_nat_republish_sched, "nat_republish", "core", 0, NULL,
713  }
714 }
715 
717 {
718  switch_stream_handle_t stream = { 0 };
719  SWITCH_STANDARD_STREAM(stream);
720 
721  stream.write_function(&stream, "Nat Type: %s, ExtIP: %s\n",
722  (nat_globals.nat_type == SWITCH_NAT_TYPE_UPNP) ? "UPNP" : (nat_globals.nat_type == SWITCH_NAT_TYPE_PMP ? "NAT-PMP" : "UNKNOWN"),
723  nat_globals.pub_addr);
724 
725  if (nat_globals.mapping) {
726  stream.write_function(&stream, "NAT port mapping enabled.\n");
727  } else {
728  stream.write_function(&stream, "NAT port mapping disabled.\n");
729  }
730 
731  switch_api_execute("show", "nat_map", NULL, &stream);
732 
733  return stream.data; /* caller frees */
734 }
735 
737 {
738  return initialized;
739 }
740 
742 {
744  FreeUPNPUrls(&nat_globals.urls);
745  switch_safe_free(nat_globals.descURL);
746 }
747 
748 
749 /* For Emacs:
750  * Local Variables:
751  * mode:c
752  * indent-tabs-mode:t
753  * tab-width:4
754  * c-basic-offset:4
755  * End:
756  * For VIM:
757  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
758  */
static int get_pmp_pubaddr(char *pub_addr)
Definition: switch_nat.c:147
switch_nat_type_t
Definition: switch_nat.h:41
#define switch_event_fire(event)
Fire an event filling in most of the arguements with obvious values.
Definition: switch_event.h:412
void switch_xml_free(_In_opt_ switch_xml_t xml)
frees the memory allocated for an switch_xml structure
#define SWITCH_THREAD_FUNC
void switch_nat_shutdown(void)
Shuts down the NAT Traversal System.
Definition: switch_nat.c:741
#define SWITCH_CHANNEL_LOG
#define IP_LEN
Definition: switch_nat.c:43
switch_xml_t switch_xml_find_child(_In_ switch_xml_t node, _In_z_ const char *childname, _In_opt_z_ const char *attrname, _In_opt_z_ const char *value)
find a child tag in a node called 'childname' with an attribute 'attrname' which equals 'value' ...
switch_status_t switch_socket_bind(switch_socket_t *sock, switch_sockaddr_t *sa)
Definition: switch_apr.c:719
#define SWITCH_STATUS_IS_BREAK(x)
Definition: switch_utils.h:564
struct UPNPUrls urls
Definition: switch_nat.c:49
int switch_wait_sock(switch_os_socket_t sock, uint32_t ms, switch_poll_t flags)
#define switch_xml_next(xml)
returns the next tag of the same name in the same section and depth or NULL \ if not found ...
Definition: switch_xml.h:170
char nat_type_str[5]
Definition: switch_nat.c:48
switch_status_t switch_nat_add_mapping_internal(switch_port_t port, switch_nat_ip_proto_t proto, switch_port_t *external_port, switch_bool_t sticky, switch_bool_t publish)
Definition: switch_nat.c:580
void switch_nat_reinit(void)
re-initializes NAT subsystem
Definition: switch_nat.c:215
switch_bool_t
Definition: switch_types.h:405
switch_status_t switch_api_execute(const char *cmd, const char *arg, switch_core_session_t *session, switch_stream_handle_t *stream)
Execute a registered API command.
switch_memory_pool_t * pool
static switch_bool_t first_init
Definition: switch_nat.c:68
switch_status_t switch_event_add_header(switch_event_t *event, switch_stack_t stack, const char *header_name, const char *fmt,...) PRINTF_FUNCTION(4
Add a header to an event.
Representation of an event.
Definition: switch_event.h:80
struct IGDdatas data
Definition: switch_nat.c:50
void switch_core_set_variable(_In_z_ const char *varname, _In_opt_z_ const char *value)
Add a global variable to the core.
switch_status_t switch_nat_add_mapping(switch_port_t port, switch_nat_ip_proto_t proto, switch_port_t *external_port, switch_bool_t sticky)
Maps a port through the NAT Traversal System.
Definition: switch_nat.c:619
A representation of an XML tree.
Definition: switch_xml.h:76
switch_socket_t * msocket
Definition: switch_nat.c:63
static switch_status_t switch_nat_add_mapping_upnp(switch_port_t port, switch_nat_ip_proto_t proto)
Definition: switch_nat.c:491
static switch_thread_t * thread
Definition: switch_log.c:279
switch_status_t switch_socket_recvfrom(switch_sockaddr_t *from, switch_socket_t *sock, int32_t flags, char *buf, size_t *len)
Definition: switch_apr.c:936
uint32_t switch_scheduler_add_task(time_t task_runtime, switch_scheduler_func_t func, const char *desc, const char *group, uint32_t cmd_id, void *cmd_arg, switch_scheduler_flag_t flags)
Schedule a task in the future.
char * txt
Definition: switch_xml.h:82
switch_status_t switch_thread_join(switch_status_t *retval, switch_thread_t *thd)
Definition: switch_apr.c:1255
void switch_nat_set_mapping(switch_bool_t mapping)
Update the setting if port mapping will be created.
Definition: switch_nat.c:210
const char * switch_nat_get_type(void)
Definition: switch_nat.c:575
switch_bool_t mapping
Definition: switch_nat.c:54
char * switch_nat_status(void)
Returns a list of nat mappings and other status info.
Definition: switch_nat.c:716
static void *SWITCH_THREAD_FUNC switch_nat_multicast_runtime(switch_thread_t *thread, void *obj)
Definition: switch_nat.c:266
void switch_nat_thread_start(void)
Definition: switch_nat.c:357
void switch_nat_init(switch_memory_pool_t *pool, switch_bool_t mapping)
Initilize the NAT Traversal System.
Definition: switch_nat.c:399
void switch_nat_thread_stop(void)
Definition: switch_nat.c:371
switch_byte_t switch_byte_t * buf
switch_bool_t switch_nat_is_initialized(void)
Has the NAT subsystem been initialized.
Definition: switch_nat.c:736
#define switch_yield(ms)
Wait a desired number of microseconds and yield the CPU.
Definition: switch_utils.h:908
struct apr_sockaddr_t switch_sockaddr_t
Definition: switch_apr.h:1029
switch_memory_pool_t * pool
Definition: switch_nat.c:60
switch_status_t switch_event_add_header_string(switch_event_t *event, switch_stack_t stack, const char *header_name, const char *data)
Add a string header to an event.
static switch_status_t switch_nat_del_mapping_upnp(switch_port_t port, switch_nat_ip_proto_t proto)
Definition: switch_nat.c:553
#define switch_safe_free(it)
Free a pointer and set it to NULL unless it already is NULL.
Definition: switch_utils.h:789
#define NAT_REFRESH_INTERVAL
Definition: switch_nat.c:44
switch_status_t switch_socket_opt_set(switch_socket_t *sock, int32_t opt, int32_t on)
Definition: switch_apr.c:823
#define MULTICAST_BUFFSIZE
Definition: switch_nat.c:42
uint16_t switch_port_t
char * descURL
Definition: switch_nat.c:51
#define zstr_buf(s)
Definition: switch_utils.h:285
#define SWITCH_STANDARD_STREAM(s)
char * switch_core_get_variable(_In_z_ const char *varname)
Retrieve a global variable from the core.
switch_nat_type_t nat_type
Definition: switch_nat.c:47
char * switch_copy_string(_Out_z_cap_(dst_size) char *dst, _In_z_ const char *src, _In_ switch_size_t dst_size)
switch_status_t switch_nat_del_mapping(switch_port_t port, switch_nat_ip_proto_t proto)
Deletes a NAT mapping.
Definition: switch_nat.c:625
#define switch_xml_parse_str_dup(x)
Parses a string into a switch_xml_t.
Definition: switch_xml.h:117
void switch_nat_late_init(void)
Initilize the rest of the NAT Traversal System.
Definition: switch_nat.c:708
char pub_addr[IP_LEN]
Definition: switch_nat.c:52
static switch_status_t switch_nat_del_mapping_pmp(switch_port_t port, switch_nat_ip_proto_t proto)
Definition: switch_nat.c:516
static switch_status_t get_upnp_pubaddr(char *pub_addr)
Definition: switch_nat.c:71
switch_sockaddr_t * maddress
Definition: switch_nat.c:62
switch_status_t switch_socket_create(switch_socket_t **new_sock, int family, int type, int protocol, switch_memory_pool_t *pool)
Definition: switch_apr.c:704
switch_stream_handle_write_function_t write_function
switch_status_t
Common return values.
#define SWITCH_SO_NONBLOCK
Definition: switch_apr.h:994
switch_status_t switch_socket_close(switch_socket_t *sock)
Definition: switch_apr.c:714
#define SWITCH_UNSPEC
Definition: switch_apr.h:1022
struct apr_thread_t switch_thread_t
Definition: switch_apr.h:941
Main Library Header.
#define switch_event_create(event, id)
Create a new event assuming it will not be custom event and therefore hiding the unused parameters...
Definition: switch_event.h:383
#define SWITCH_DECLARE(type)
switch_status_t init_nat_monitor(switch_memory_pool_t *pool)
Definition: switch_nat.c:220
switch_xml_t switch_xml_child(_In_ switch_xml_t xml, _In_z_ const char *name)
returns the first child tag (one level deeper) with the given name or NULL \ if not found ...
static nat_globals_perm_t nat_globals_perm
Definition: switch_nat.c:66
#define switch_set_string(_dst, _src)
Definition: switch_utils.h:665
static int init_pmp(void)
Definition: switch_nat.c:205
#define SWITCH_SO_REUSEADDR
Definition: switch_apr.h:995
time_t switch_epoch_time_now(time_t *t)
Get the current epoch time.
Definition: switch_time.c:321
switch_status_t switch_mcast_join(switch_socket_t *sock, switch_sockaddr_t *join, switch_sockaddr_t *iface, switch_sockaddr_t *source)
Definition: switch_apr.c:871
switch_thread_t * nat_thread_p
Definition: switch_nat.c:355
struct apr_pool_t switch_memory_pool_t
void switch_log_printf(_In_ switch_text_channel_t channel, _In_z_ const char *file, _In_z_ const char *func, _In_ int line, _In_opt_z_ const char *userdata, _In_ switch_log_level_t level, _In_z_ _Printf_format_string_ const char *fmt,...) PRINTF_FUNCTION(7
Write log data to the logging engine.
const char * switch_stristr(const char *instr, const char *str)
switch_status_t switch_threadattr_create(switch_threadattr_t **new_attr, switch_memory_pool_t *pool)
Definition: switch_apr.c:642
switch_status_t switch_thread_create(switch_thread_t **new_thread, switch_threadattr_t *attr, switch_thread_start_t func, void *data, switch_memory_pool_t *cont)
Definition: switch_apr.c:675
switch_status_t switch_find_local_ip(_Out_opt_bytecapcount_(len) char *buf, _In_ int len, _In_opt_ int *mask, _In_ int family)
find local ip of the box
#define TRUE
static switch_bool_t initialized
Definition: switch_nat.c:69
SWITCH_STANDARD_SCHED_FUNC(switch_nat_republish_sched)
Definition: switch_nat.c:700
void switch_nat_republish(void)
Republishes the nap mappings.
Definition: switch_nat.c:652
struct apr_socket_t switch_socket_t
Definition: switch_apr.h:1026
#define switch_assert(expr)
static int init_upnp(void)
Definition: switch_nat.c:86
switch_status_t switch_sockaddr_info_get(switch_sockaddr_t **sa, const char *hostname, int32_t family, switch_port_t port, int32_t flags, switch_memory_pool_t *pool)
Definition: switch_apr.c:817
static nat_globals_t nat_globals
Definition: switch_nat.c:57
static switch_status_t switch_nat_add_mapping_pmp(switch_port_t port, switch_nat_ip_proto_t proto, switch_port_t *external_port)
Definition: switch_nat.c:444
memset(buf, 0, buflen)
char pvt_addr[IP_LEN]
Definition: switch_nat.c:53
switch_nat_ip_proto_t
Definition: switch_nat.h:47