void natpmp_uninit(struct natpmp_handle_t **handle) { // Remove all port mapping associated with this host struct natpmp_handle_t *m = *handle; sendnewportmappingrequest(&m->natpmp, NATPMP_PROTOCOL_TCP, 0, 0, 0); sendnewportmappingrequest(&m->natpmp, NATPMP_PROTOCOL_UDP, 0, 0, 0); closenatpmp(&m->natpmp); free(*handle); *handle = NULL; }
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<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; }
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; }
int tr_natpmpPulse( struct tr_natpmp * nat, tr_port private_port, bool is_enabled, tr_port * public_port ) { int ret; if( is_enabled && ( nat->state == TR_NATPMP_DISCOVER ) ) { int val = initnatpmp( &nat->natpmp ); logVal( "initnatpmp", val ); val = sendpublicaddressrequest( &nat->natpmp ); logVal( "sendpublicaddressrequest", val ); nat->state = val < 0 ? TR_NATPMP_ERR : TR_NATPMP_RECV_PUB; nat->has_discovered = true; setCommandTime( nat ); } if( ( nat->state == TR_NATPMP_RECV_PUB ) && canSendCommand( nat ) ) { natpmpresp_t response; const int val = readnatpmpresponseorretry( &nat->natpmp, &response ); logVal( "readnatpmpresponseorretry", val ); if( val >= 0 ) { char str[128]; evutil_inet_ntop( AF_INET, &response.pnu.publicaddress.addr, str, sizeof( str ) ); tr_ninf( getKey( ), _( "Found public address \"%s\"" ), str ); nat->state = TR_NATPMP_IDLE; } else if( val != NATPMP_TRYAGAIN ) { nat->state = TR_NATPMP_ERR; } } if( ( nat->state == TR_NATPMP_IDLE ) || ( nat->state == TR_NATPMP_ERR ) ) { if( nat->is_mapped && ( !is_enabled || ( nat->private_port != private_port ) ) ) nat->state = TR_NATPMP_SEND_UNMAP; } if( ( nat->state == TR_NATPMP_SEND_UNMAP ) && canSendCommand( nat ) ) { const int val = sendnewportmappingrequest( &nat->natpmp, NATPMP_PROTOCOL_TCP, nat->private_port, nat->public_port, 0 ); logVal( "sendnewportmappingrequest", val ); nat->state = val < 0 ? TR_NATPMP_ERR : TR_NATPMP_RECV_UNMAP; setCommandTime( nat ); } if( nat->state == TR_NATPMP_RECV_UNMAP ) { natpmpresp_t resp; const int val = readnatpmpresponseorretry( &nat->natpmp, &resp ); logVal( "readnatpmpresponseorretry", val ); if( val >= 0 ) { const int private_port = resp.pnu.newportmapping.privateport; tr_ninf( getKey( ), _( "no longer forwarding port %d" ), private_port ); if( nat->private_port == private_port ) { nat->private_port = 0; nat->public_port = 0; nat->state = TR_NATPMP_IDLE; nat->is_mapped = false; } } else if( val != NATPMP_TRYAGAIN ) { nat->state = TR_NATPMP_ERR; } } if( nat->state == TR_NATPMP_IDLE ) { if( is_enabled && !nat->is_mapped && nat->has_discovered ) nat->state = TR_NATPMP_SEND_MAP; else if( nat->is_mapped && tr_time( ) >= nat->renew_time ) nat->state = TR_NATPMP_SEND_MAP; } if( ( nat->state == TR_NATPMP_SEND_MAP ) && canSendCommand( nat ) ) { const int val = sendnewportmappingrequest( &nat->natpmp, NATPMP_PROTOCOL_TCP, private_port, private_port, LIFETIME_SECS ); logVal( "sendnewportmappingrequest", val ); nat->state = val < 0 ? TR_NATPMP_ERR : TR_NATPMP_RECV_MAP; setCommandTime( nat ); } if( nat->state == TR_NATPMP_RECV_MAP ) { natpmpresp_t resp; const int val = readnatpmpresponseorretry( &nat->natpmp, &resp ); logVal( "readnatpmpresponseorretry", val ); if( val >= 0 ) { nat->state = TR_NATPMP_IDLE; nat->is_mapped = true; nat->renew_time = tr_time( ) + ( resp.pnu.newportmapping.lifetime / 2 ); nat->private_port = resp.pnu.newportmapping.privateport; nat->public_port = resp.pnu.newportmapping.mappedpublicport; tr_ninf( getKey( ), _( "Port %d forwarded successfully" ), nat->private_port ); } else if( val != NATPMP_TRYAGAIN ) { nat->state = TR_NATPMP_ERR; } } switch( nat->state ) { case TR_NATPMP_IDLE: *public_port = nat->public_port; return nat->is_mapped ? TR_PORT_MAPPED : TR_PORT_UNMAPPED; break; case TR_NATPMP_DISCOVER: ret = TR_PORT_UNMAPPED; break; case TR_NATPMP_RECV_PUB: case TR_NATPMP_SEND_MAP: case TR_NATPMP_RECV_MAP: ret = TR_PORT_MAPPING; break; case TR_NATPMP_SEND_UNMAP: case TR_NATPMP_RECV_UNMAP: ret = TR_PORT_UNMAPPING; break; default: ret = TR_PORT_ERROR; break; } return ret; }
int natpmp_handler(struct natpmp_handle_t *handle, uint16_t port, time_t lifespan, time_t now) { natpmpresp_t response; // Retry later if we want to wait longer if (handle->retry > now) { return PF_RETRY; } #ifdef DEBUG log_debug("NAT-PMP: Handle port: %hu, lifespan: %ld, state: %s", port, lifespan, natpmp_statestr(handle->state)); #endif // Initialize data structure / socket if (handle->state == NATPMP_STATE_INIT) { int rc = initnatpmp(&handle->natpmp, 0, 0); if (rc >= 0) { handle->state = NATPMP_STATE_REQUEST_GATEWAY; return PF_RETRY; } else { log_debug("NAT-PMP: Method initnatpmp returned %d.", rc); goto error; } } // Request gateway address if (handle->state == NATPMP_STATE_REQUEST_GATEWAY) { int rc = sendpublicaddressrequest(&handle->natpmp); if (rc >= 0) { handle->retry = now + 8; handle->state = NATPMP_STATE_RECEIVE_GATEWAY; return PF_RETRY; } else { log_debug("NAT-PMP: Method sendpublicaddressrequest returned %d.", rc); goto error; } } // Read public gateway address if (handle->state == NATPMP_STATE_RECEIVE_GATEWAY) { int rc = readnatpmpresponseorretry(&handle->natpmp, &response); if (rc >= 0) { char str[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &response.pnu.publicaddress.addr, str, sizeof (str)); log_info("NAT-PMP: Found public address \"%s\".", str); handle->state = NATPMP_STATE_REQUEST_PORTMAPPING; return PF_RETRY; } else if (rc == NATPMP_TRYAGAIN) { handle->retry = now + (10 * 60); handle->state = NATPMP_STATE_REQUEST_GATEWAY; return PF_RETRY; } else { log_debug("NAT-PMP: Method readnatpmpresponseorretry returned %d.", rc); goto error; } } // Add/Remove port mappings if (handle->state == NATPMP_STATE_REQUEST_PORTMAPPING) { int rc_udp = sendnewportmappingrequest(&handle->natpmp, NATPMP_PROTOCOL_UDP, port, port, lifespan); int rc_tcp = sendnewportmappingrequest(&handle->natpmp, NATPMP_PROTOCOL_TCP, port, port, lifespan); if (rc_udp >= 0 && rc_tcp >= 0) { handle->retry = now + 2; handle->state = NATPMP_STATE_RECEIVE_PORTMAPPING; return PF_RETRY; } else { log_debug("NAT-PMP: Method sendnewportmappingrequest returned an error: %s", strnatpmperr((rc_udp >= 0) ? rc_tcp : rc_udp)); goto error; } } // Check port mapping if (handle->state == NATPMP_STATE_RECEIVE_PORTMAPPING) { int rc = readnatpmpresponseorretry(&handle->natpmp, &response); if (rc >= 0) { int private_port = response.pnu.newportmapping.privateport; int public_port = response.pnu.newportmapping.mappedpublicport; time_t lifetime = response.pnu.newportmapping.lifetime; if (lifetime > 0) { log_info("NAT-PMP: Port forwarding added for port %d (to private port %d) for %ld seconds.", public_port, private_port, lifetime); handle->state = NATPMP_STATE_REQUEST_PORTMAPPING; return PF_DONE; } else { log_debug("NAT-PMP: Port forwarding removed for public port %d (to private port %d) for %ld seconds.", public_port, private_port, lifetime); handle->state = NATPMP_STATE_REQUEST_PORTMAPPING; return PF_DONE; } } else if (rc == NATPMP_TRYAGAIN) { handle->state = NATPMP_STATE_RECEIVE_PORTMAPPING; return PF_RETRY; } else { log_debug("NAT-PMP: Port forwarding failed for port %d.", port); goto error; } } error:; handle->retry = now + 60; handle->state = NATPMP_STATE_ERROR; return PF_ERROR; }
static int natpmpPulse( ml_upnpmp_t * map ) { int ret; if( map->enabled && ( map->natpmpState == ML_NATPMP_DISCOVER ) ) { int val = initnatpmp( &map->natpmp, 0, 0 ); dbg_printf( "initnatpmp = %d\n", val ); val = sendpublicaddressrequest( &map->natpmp ); dbg_printf( "sendpublicaddressrequest = %d\n", val ); map->natpmpState = val < 0 ? ML_NATPMP_ERR : ML_NATPMP_RECV_PUB; map->natpmpDiscovered = 1; setCommandTime( map ); } if( ( map->natpmpState == ML_NATPMP_RECV_PUB ) && canSendCommand( map ) ) { natpmpresp_t response; const int val = readnatpmpresponseorretry( &map->natpmp, &response ); dbg_printf( "readnatpmpresponseorretry = %d\n", val ); if( val >= 0 ) { dbg_printf( "Found public address \"%s\"\n", inet_ntoa( response.pnu.publicaddress.addr ) ); map->natpmpState = ML_NATPMP_IDLE; } else if( val != NATPMP_TRYAGAIN ) { map->natpmpState = ML_NATPMP_ERR; } } if( ( map->natpmpState == ML_NATPMP_IDLE ) || ( map->natpmpState == ML_NATPMP_ERR ) ) { if( map->natpmpMapped && ( ! map->enabled ) ) map->natpmpState = ML_NATPMP_SEND_UNMAP; } if( ( map->natpmpState == ML_NATPMP_SEND_UNMAP ) && canSendCommand( map ) ) { const int val = sendnewportmappingrequest( &map->natpmp, NATPMP_PROTOCOL_TCP, map->intPort, map->extPort, 0 ); dbg_printf( "sendnewportmappingrequest = %d\n", val ); map->natpmpState = val < 0 ? ML_NATPMP_ERR : ML_NATPMP_RECV_UNMAP; setCommandTime( map ); } if( map->natpmpState == ML_NATPMP_RECV_UNMAP ) { natpmpresp_t resp; const int val = readnatpmpresponseorretry( &map->natpmp, &resp ); dbg_printf( "readnatpmpresponseorretry = %d\n", val ); if( val >= 0 ) { const int p = resp.pnu.newportmapping.privateport; dbg_printf( "no longer forwarding port %d\n", p ); if( map->extPort == p ) { map->extPort = 0; map->natpmpState = ML_NATPMP_IDLE; map->natpmpMapped = 0; } } else if( val != NATPMP_TRYAGAIN ) { map->natpmpState = ML_NATPMP_ERR; } } if( map->natpmpState == ML_NATPMP_IDLE ) { if( map->enabled && !map->natpmpMapped && map->natpmpDiscovered ) map->natpmpState = ML_NATPMP_SEND_MAP; else if( map->natpmpMapped && time(NULL) >= map->renewTime ) map->natpmpState = ML_NATPMP_SEND_MAP; } if( ( map->natpmpState == ML_NATPMP_SEND_MAP ) && canSendCommand( map ) ) { const int val = sendnewportmappingrequest( &map->natpmp, NATPMP_PROTOCOL_TCP, map->intPort, map->extPort, LIFETIME_SECS ); dbg_printf( "sendnewportmappingrequest = %d\n", val ); map->natpmpState = val < 0 ? ML_NATPMP_ERR : ML_NATPMP_RECV_MAP; setCommandTime( map ); } if( map->natpmpState == ML_NATPMP_RECV_MAP ) { natpmpresp_t resp; const int val = readnatpmpresponseorretry( &map->natpmp, &resp ); dbg_printf( "readnatpmpresponseorretry = %d\n", val ); if( val >= 0 ) { map->natpmpState = ML_NATPMP_IDLE; map->natpmpMapped = 1; map->renewTime = time(NULL) + LIFETIME_SECS; map->extPort = resp.pnu.newportmapping.privateport; dbg_printf( "Port %d forwarded successfully\n", map->extPort ); } else if( val != NATPMP_TRYAGAIN ) { map->natpmpState = ML_NATPMP_ERR; } } switch( map->natpmpState ) { case ML_NATPMP_IDLE: ret = map->natpmpMapped ? ML_PORT_MAPPED : ML_PORT_UNMAPPED; break; case ML_NATPMP_DISCOVER: ret = ML_PORT_UNMAPPED; break; case ML_NATPMP_RECV_PUB: case ML_NATPMP_SEND_MAP: case ML_NATPMP_RECV_MAP: ret = ML_PORT_MAPPING; break; case ML_NATPMP_SEND_UNMAP: case ML_NATPMP_RECV_UNMAP: ret = ML_PORT_UNMAPPING; break; default: ret = ML_PORT_ERROR; break; } return ret; }
int tr_natpmpPulse( struct tr_natpmp * nat, int port, int isEnabled ) { int ret; if( isEnabled && ( nat->state == TR_NATPMP_DISCOVER ) ) { int val = initnatpmp( &nat->natpmp ); logVal( "initnatpmp", val ); val = sendpublicaddressrequest( &nat->natpmp ); logVal( "sendpublicaddressrequest", val ); nat->state = val < 0 ? TR_NATPMP_ERR : TR_NATPMP_RECV_PUB; nat->hasDiscovered = 1; setCommandTime( nat ); } if( ( nat->state == TR_NATPMP_RECV_PUB ) && canSendCommand( nat ) ) { natpmpresp_t response; const int val = readnatpmpresponseorretry( &nat->natpmp, &response ); logVal( "readnatpmpresponseorretry", val ); if( val >= 0 ) { tr_ninf( getKey( ), _( "Found public address \"%s\"" ), inet_ntoa( response.pnu.publicaddress.addr ) ); nat->state = TR_NATPMP_IDLE; } else if( val != NATPMP_TRYAGAIN ) { nat->state = TR_NATPMP_ERR; } } if( ( nat->state == TR_NATPMP_IDLE ) || ( nat->state == TR_NATPMP_ERR ) ) { if( nat->isMapped && ( !isEnabled || ( nat->port != port ) ) ) nat->state = TR_NATPMP_SEND_UNMAP; } if( ( nat->state == TR_NATPMP_SEND_UNMAP ) && canSendCommand( nat ) ) { const int val = sendnewportmappingrequest( &nat->natpmp, NATPMP_PROTOCOL_TCP, nat->port, nat->port, 0 ); logVal( "sendnewportmappingrequest", val ); nat->state = val < 0 ? TR_NATPMP_ERR : TR_NATPMP_RECV_UNMAP; setCommandTime( nat ); } if( nat->state == TR_NATPMP_RECV_UNMAP ) { natpmpresp_t resp; const int val = readnatpmpresponseorretry( &nat->natpmp, &resp ); logVal( "readnatpmpresponseorretry", val ); if( val >= 0 ) { const int p = resp.pnu.newportmapping.privateport; tr_ninf( getKey( ), _( "no longer forwarding port %d" ), p ); if( nat->port == p ) { nat->port = -1; nat->state = TR_NATPMP_IDLE; nat->isMapped = 0; } } else if( val != NATPMP_TRYAGAIN ) { nat->state = TR_NATPMP_ERR; } } if( nat->state == TR_NATPMP_IDLE ) { if( isEnabled && !nat->isMapped && nat->hasDiscovered ) nat->state = TR_NATPMP_SEND_MAP; else if( nat->isMapped && tr_time( ) >= nat->renewTime ) nat->state = TR_NATPMP_SEND_MAP; } if( ( nat->state == TR_NATPMP_SEND_MAP ) && canSendCommand( nat ) ) { const int val = sendnewportmappingrequest( &nat->natpmp, NATPMP_PROTOCOL_TCP, port, port, LIFETIME_SECS ); logVal( "sendnewportmappingrequest", val ); nat->state = val < 0 ? TR_NATPMP_ERR : TR_NATPMP_RECV_MAP; setCommandTime( nat ); } if( nat->state == TR_NATPMP_RECV_MAP ) { natpmpresp_t resp; const int val = readnatpmpresponseorretry( &nat->natpmp, &resp ); logVal( "readnatpmpresponseorretry", val ); if( val >= 0 ) { nat->state = TR_NATPMP_IDLE; nat->isMapped = 1; nat->renewTime = tr_time( ) + LIFETIME_SECS; nat->port = resp.pnu.newportmapping.privateport; tr_ninf( getKey( ), _( "Port %d forwarded successfully" ), nat->port ); } else if( val != NATPMP_TRYAGAIN ) { nat->state = TR_NATPMP_ERR; } } switch( nat->state ) { case TR_NATPMP_IDLE: ret = nat->isMapped ? TR_PORT_MAPPED : TR_PORT_UNMAPPED; break; case TR_NATPMP_DISCOVER: ret = TR_PORT_UNMAPPED; break; case TR_NATPMP_RECV_PUB: case TR_NATPMP_SEND_MAP: case TR_NATPMP_RECV_MAP: ret = TR_PORT_MAPPING; break; case TR_NATPMP_SEND_UNMAP: case TR_NATPMP_RECV_UNMAP: ret = TR_PORT_UNMAPPING; break; default: ret = TR_PORT_ERROR; break; } return ret; }