bool NATPMPInterface::removePortForward(const NATPortMapping& mapping) { if (sendnewportmappingrequest(&p->natpmp, mapping.getProtocol() == NATPortMapping::TCP ? NATPMP_PROTOCOL_TCP : NATPMP_PROTOCOL_UDP, 0, 0, mapping.getLocalPort()) < 0) { SWIFT_LOG(debug) << "Failed to send NAT-PMP remove forwarding request!" << std::endl; return false; } int r = 0; natpmpresp_t response; do { fd_set fds; struct timeval timeout; FD_ZERO(&fds); FD_SET(p->natpmp.s, &fds); getnatpmprequesttimeout(&p->natpmp, &timeout); select(FD_SETSIZE, &fds, NULL, NULL, &timeout); r = readnatpmpresponseorretry(&p->natpmp, &response); } while(r == NATPMP_TRYAGAIN); if (r == 0) { return true; } else { SWIFT_LOG(debug) << "Invalid NAT-PMP response." << std::endl; return false; } }
boost::optional<HostAddress> NATPMPInterface::getPublicIP() { if (sendpublicaddressrequest(&p->natpmp) < 0) { SWIFT_LOG(debug) << "Failed to send NAT-PMP public address request!" << std::endl; return boost::optional<HostAddress>(); } int r = 0; natpmpresp_t response; do { fd_set fds; struct timeval timeout; FD_ZERO(&fds); FD_SET(p->natpmp.s, &fds); getnatpmprequesttimeout(&p->natpmp, &timeout); select(FD_SETSIZE, &fds, NULL, NULL, &timeout); r = readnatpmpresponseorretry(&p->natpmp, &response); } while (r == NATPMP_TRYAGAIN); if (r == 0) { return boost::optional<HostAddress>(HostAddress(reinterpret_cast<const unsigned char*>(&(response.pnu.publicaddress.addr)), 4)); } else { SWIFT_LOG(debug) << "Inavlid NAT-PMP response." << std::endl; return boost::optional<HostAddress>(); } }
boost::optional<NATPortMapping> NATPMPInterface::addPortForward(int localPort, int publicPort) { NATPortMapping mapping(localPort, publicPort, NATPortMapping::TCP); if (sendnewportmappingrequest(&p->natpmp, mapping.getProtocol() == NATPortMapping::TCP ? NATPMP_PROTOCOL_TCP : NATPMP_PROTOCOL_UDP, mapping.getLeaseInSeconds(), mapping.getPublicPort(), mapping.getLocalPort()) < 0) { SWIFT_LOG(debug) << "Failed to send NAT-PMP port forwarding request!" << std::endl; return boost::optional<NATPortMapping>(); } int r = 0; natpmpresp_t response; do { fd_set fds; struct timeval timeout; FD_ZERO(&fds); FD_SET(p->natpmp.s, &fds); getnatpmprequesttimeout(&p->natpmp, &timeout); select(FD_SETSIZE, &fds, NULL, NULL, &timeout); r = readnatpmpresponseorretry(&p->natpmp, &response); } while(r == NATPMP_TRYAGAIN); if (r == 0) { NATPortMapping result(response.pnu.newportmapping.privateport, response.pnu.newportmapping.mappedpublicport, NATPortMapping::TCP, response.pnu.newportmapping.lifetime); return result; } else { SWIFT_LOG(debug) << "Invalid NAT-PMP response." << std::endl; return boost::optional<NATPortMapping>(); } }
int tor_natpmp_add_tcp_mapping(uint16_t internal_port, uint16_t external_port, int is_verbose, void *backend_state) { int r = 0; int x = 0; int sav_errno; natpmp_state_t *state = (natpmp_state_t *) backend_state; struct timeval timeout; if (is_verbose) fprintf(stderr, "V: sending natpmp portmapping request...\n"); r = sendnewportmappingrequest(&(state->natpmp), state->protocol, internal_port, external_port, state->lease); if (is_verbose) fprintf(stderr, "tor-fw-helper: NAT-PMP sendnewportmappingrequest " "returned %d (%s)\n", r, r==12?"SUCCESS":"FAILED"); do { getnatpmprequesttimeout(&(state->natpmp), &timeout); x = wait_until_fd_readable(state->natpmp.s, &timeout); if (x == -1) return -1; if (is_verbose) fprintf(stderr, "V: attempting to readnatpmpreponseorretry...\n"); r = readnatpmpresponseorretry(&(state->natpmp), &(state->response)); sav_errno = tor_socket_errno(state->natpmp.s); if (r<0 && r!=NATPMP_TRYAGAIN) { fprintf(stderr, "E: readnatpmpresponseorretry failed %d\n", r); fprintf(stderr, "E: errno=%d '%s'\n", sav_errno, tor_socket_strerror(sav_errno)); } } while (r == NATPMP_TRYAGAIN); if (r != 0) { /* XXX TODO: NATPMP_* should be formatted into useful error strings */ fprintf(stderr, "E: NAT-PMP It appears that something went wrong:" " %d\n", r); if (r == -51) fprintf(stderr, "E: NAT-PMP It appears that the request was " "unauthorized\n"); return r; } if (r == NATPMP_SUCCESS) { fprintf(stderr, "tor-fw-helper: NAT-PMP mapped public port %hu to" " localport %hu liftime %u\n", (state->response).pnu.newportmapping.mappedpublicport, (state->response).pnu.newportmapping.privateport, (state->response).pnu.newportmapping.lifetime); } return (r == NATPMP_SUCCESS) ? 0 : -1; }
/** Fetch our likely public IP from our upstream NAT-PMP enabled NAT device. * Use the connection context stored in <b>backend_state</b>. */ int tor_natpmp_fetch_public_ip(tor_fw_options_t *tor_fw_options, void *backend_state) { int r = 0; int x = 0; int sav_errno; natpmp_state_t *state = (natpmp_state_t *) backend_state; struct timeval timeout; r = sendpublicaddressrequest(&(state->natpmp)); fprintf(stdout, "tor-fw-helper: NAT-PMP sendpublicaddressrequest returned" " %d (%s)\n", r, r==2?"SUCCESS":"FAILED"); do { getnatpmprequesttimeout(&(state->natpmp), &timeout); x = wait_until_fd_readable(state->natpmp.s, &timeout); if (x == -1) return -1; if (tor_fw_options->verbose) fprintf(stdout, "V: NAT-PMP attempting to read reponse...\n"); r = readnatpmpresponseorretry(&(state->natpmp), &(state->response)); sav_errno = errno; if (tor_fw_options->verbose) fprintf(stdout, "V: NAT-PMP readnatpmpresponseorretry returned" " %d\n", r); if ( r < 0 && r != NATPMP_TRYAGAIN) { fprintf(stderr, "E: NAT-PMP readnatpmpresponseorretry failed %d\n", r); fprintf(stderr, "E: NAT-PMP errno=%d '%s'\n", sav_errno, strerror(sav_errno)); } } while (r == NATPMP_TRYAGAIN ); if (r != 0) { fprintf(stderr, "E: NAT-PMP It appears that something went wrong:" " %d\n", r); return r; } fprintf(stdout, "tor-fw-helper: ExternalIPAddress = %s\n", inet_ntoa((state->response).pnu.publicaddress.addr)); tor_fw_options->public_ip_status = 1; if (tor_fw_options->verbose) { fprintf(stdout, "V: result = %u\n", r); fprintf(stdout, "V: type = %u\n", (state->response).type); fprintf(stdout, "V: resultcode = %u\n", (state->response).resultcode); fprintf(stdout, "V: epoch = %u\n", (state->response).epoch); } return r; }
static int get_pmp_pubaddr(char *pub_addr) { int r = 0, i = 0, max = 5; natpmpresp_t response; char *pubaddr = NULL; fd_set fds; natpmp_t natpmp; const char *err = NULL; if ((r = initnatpmp(&natpmp)) < 0) { err = "init failed"; goto end; } if ((r = sendpublicaddressrequest(&natpmp)) < 0) { err = "pub addr req failed"; goto end; } do { struct timeval timeout = { 1, 0 }; i++; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Checking for PMP %d/%d\n", i, max); FD_ZERO(&fds); FD_SET(natpmp.s, &fds); if ((r = getnatpmprequesttimeout(&natpmp, &timeout)) < 0) { err = "get timeout failed"; goto end; } if ((r = select(FD_SETSIZE, &fds, NULL, NULL, &timeout)) < 0) { err = "select failed"; goto end; } r = readnatpmpresponseorretry(&natpmp, &response); } while (r == NATPMP_TRYAGAIN && i < max); if (r < 0) { err = "general error"; goto end; } pubaddr = inet_ntoa(response.pnu.publicaddress.addr); switch_copy_string(pub_addr, pubaddr, IP_LEN); nat_globals.nat_type = SWITCH_NAT_TYPE_PMP; closenatpmp(&natpmp); end: if (err) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error checking for PMP [%s]\n", err); } return r; }
static switch_status_t switch_nat_add_mapping_pmp(switch_port_t port, switch_nat_ip_proto_t proto, switch_port_t * external_port) { switch_status_t status = SWITCH_STATUS_FALSE; natpmpresp_t response; int r; natpmp_t natpmp; initnatpmp(&natpmp); if (proto == SWITCH_NAT_TCP) { sendnewportmappingrequest(&natpmp, NATPMP_PROTOCOL_TCP, port, port, 31104000); } else if (proto == SWITCH_NAT_UDP) { sendnewportmappingrequest(&natpmp, NATPMP_PROTOCOL_UDP, port, port, 31104000); } do { fd_set fds; struct timeval timeout = { 1, 0 }; FD_ZERO(&fds); FD_SET(natpmp.s, &fds); getnatpmprequesttimeout(&natpmp, &timeout); select(FD_SETSIZE, &fds, NULL, NULL, &timeout); r = readnatpmpresponseorretry(&natpmp, &response); } while (r == NATPMP_TRYAGAIN); if (r == 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "mapped public port %hu protocol %s to localport %hu\n", response.pnu.newportmapping.mappedpublicport, response.type == NATPMP_RESPTYPE_UDPPORTMAPPING ? "UDP" : (response.type == NATPMP_RESPTYPE_TCPPORTMAPPING ? "TCP" : "UNKNOWN"), response.pnu.newportmapping.privateport); if (external_port) { *external_port = response.pnu.newportmapping.mappedpublicport; } else if (response.pnu.newportmapping.mappedpublicport != response.pnu.newportmapping.privateport) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "External port %hu protocol %s was not available, it was instead mapped to %hu\n", response.pnu.newportmapping.privateport, response.type == NATPMP_RESPTYPE_UDPPORTMAPPING ? "UDP" : (response.type == NATPMP_RESPTYPE_TCPPORTMAPPING ? "TCP" : "UNKNOWN"), response.pnu.newportmapping.mappedpublicport); } status = SWITCH_STATUS_SUCCESS; } closenatpmp(&natpmp); return status; }
static switch_status_t switch_nat_del_mapping_pmp(switch_port_t port, switch_nat_ip_proto_t proto) { switch_status_t status = SWITCH_STATUS_FALSE; natpmpresp_t response; int r; natpmp_t natpmp; initnatpmp(&natpmp); if (proto == SWITCH_NAT_TCP) { sendnewportmappingrequest(&natpmp, NATPMP_PROTOCOL_TCP, port, port, 0); } else if (proto == SWITCH_NAT_UDP) { sendnewportmappingrequest(&natpmp, NATPMP_PROTOCOL_UDP, port, port, 0); } do { fd_set fds; struct timeval timeout; FD_ZERO(&fds); FD_SET(natpmp.s, &fds); getnatpmprequesttimeout(&natpmp, &timeout); select(FD_SETSIZE, &fds, NULL, NULL, &timeout); r = readnatpmpresponseorretry(&natpmp, &response); } while (r == NATPMP_TRYAGAIN); if (r == 0) { 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 */ response.type == NATPMP_RESPTYPE_UDPPORTMAPPING ? "UDP" : (response.type == NATPMP_RESPTYPE_TCPPORTMAPPING ? "TCP" : "UNKNOWN"), response.pnu.newportmapping.privateport); status = SWITCH_STATUS_SUCCESS; } closenatpmp(&natpmp); return status; }
/* sample code for using libnatpmp */ int main(int argc, char * * argv) { natpmp_t natpmp; natpmpresp_t response; int r; int sav_errno; struct timeval timeout; fd_set fds; int i; int protocol = 0; uint16_t privateport = 0; uint16_t publicport = 0; uint32_t lifetime = 3600; int command = 0; int forcegw = 0; in_addr_t gateway = 0; struct in_addr gateway_in_use; #ifdef WIN32 WSADATA wsaData; int nResult = WSAStartup(MAKEWORD(2,2), &wsaData); if(nResult != NO_ERROR) { fprintf(stderr, "WSAStartup() failed.\n"); return -1; } #endif /* argument parsing */ for(i=1; i<argc; i++) { if(argv[i][0] == '-') { switch(argv[i][1]) { case 'h': usage(stdout, argv[0]); return 0; case 'g': forcegw = 1; if(argc < i + 1) { fprintf(stderr, "Not enough arguments for option -%c\n", argv[i][1]); return 1; } gateway = inet_addr(argv[++i]); break; case 'a': command = 'a'; if(argc < i + 4) { fprintf(stderr, "Not enough arguments for option -%c\n", argv[i][1]); return 1; } i++; if(1 != sscanf(argv[i], "%hu", &publicport)) { fprintf(stderr, "%s is not a correct 16bits unsigned integer\n", argv[i]); return 1; } i++; if(1 != sscanf(argv[i], "%hu", &privateport)) { fprintf(stderr, "%s is not a correct 16bits unsigned integer\n", argv[i]); return 1; } i++; if(0 == strcasecmp(argv[i], "tcp")) protocol = NATPMP_PROTOCOL_TCP; else if(0 == strcasecmp(argv[i], "udp")) protocol = NATPMP_PROTOCOL_UDP; else { fprintf(stderr, "%s is not a valid protocol\n", argv[i]); return 1; } if(argc > i + 1) { if(1 != sscanf(argv[i+1], "%u", &lifetime)) { fprintf(stderr, "%s is not a correct 32bits unsigned integer\n", argv[i]); } else { i++; } } break; default: fprintf(stderr, "Unknown option %s\n", argv[i]); usage(stderr, argv[0]); return 1; } } else { fprintf(stderr, "Unknown option %s\n", argv[i]); usage(stderr, argv[0]); return 1; } } /* initnatpmp() */ r = initnatpmp(&natpmp, forcegw, gateway); printf("initnatpmp() returned %d (%s)\n", r, r?"FAILED":"SUCCESS"); if(r<0) return 1; gateway_in_use.s_addr = natpmp.gateway; printf("using gateway : %s\n", inet_ntoa(gateway_in_use)); /* sendpublicaddressrequest() */ r = sendpublicaddressrequest(&natpmp); printf("sendpublicaddressrequest returned %d (%s)\n", r, r==2?"SUCCESS":"FAILED"); if(r<0) return 1; do { FD_ZERO(&fds); FD_SET(natpmp.s, &fds); getnatpmprequesttimeout(&natpmp, &timeout); r = select(FD_SETSIZE, &fds, NULL, NULL, &timeout); if(r<0) { fprintf(stderr, "select()"); return 1; } r = readnatpmpresponseorretry(&natpmp, &response); sav_errno = errno; printf("readnatpmpresponseorretry returned %d (%s)\n", r, r==0?"OK":(r==NATPMP_TRYAGAIN?"TRY AGAIN":"FAILED")); if(r<0 && r!=NATPMP_TRYAGAIN) { #ifdef ENABLE_STRNATPMPERR fprintf(stderr, "readnatpmpresponseorretry() failed : %s\n", strnatpmperr(r)); #endif fprintf(stderr, " errno=%d '%s'\n", sav_errno, strerror(sav_errno)); } } while(r==NATPMP_TRYAGAIN); if(r<0) return 1; /* TODO : check that response.type == 0 */ printf("Public IP address : %s\n", inet_ntoa(response.pnu.publicaddress.addr)); printf("epoch = %u\n", response.epoch); if(command == 'a') { /* sendnewportmappingrequest() */ r = sendnewportmappingrequest(&natpmp, protocol, privateport, publicport, lifetime); printf("sendnewportmappingrequest returned %d (%s)\n", r, r==12?"SUCCESS":"FAILED"); if(r < 0) return 1; do { FD_ZERO(&fds); FD_SET(natpmp.s, &fds); getnatpmprequesttimeout(&natpmp, &timeout); select(FD_SETSIZE, &fds, NULL, NULL, &timeout); r = readnatpmpresponseorretry(&natpmp, &response); printf("readnatpmpresponseorretry returned %d (%s)\n", r, r==0?"OK":(r==NATPMP_TRYAGAIN?"TRY AGAIN":"FAILED")); } while(r==NATPMP_TRYAGAIN); if(r<0) { #ifdef ENABLE_STRNATPMPERR fprintf(stderr, "readnatpmpresponseorretry() failed : %s\n", strnatpmperr(r)); #endif return 1; } printf("Mapped public port %hu protocol %s to local port %hu " "liftime %u\n", response.pnu.newportmapping.mappedpublicport, response.type == NATPMP_RESPTYPE_UDPPORTMAPPING ? "UDP" : (response.type == NATPMP_RESPTYPE_TCPPORTMAPPING ? "TCP" : "UNKNOWN"), response.pnu.newportmapping.privateport, response.pnu.newportmapping.lifetime); printf("epoch = %u\n", response.epoch); } r = closenatpmp(&natpmp); printf("closenatpmp() returned %d (%s)\n", r, r==0?"SUCCESS":"FAILED"); if(r<0) return 1; return 0; }