Extend network traversal to local addresses
This commit is contained in:
127
src/stoon.c
127
src/stoon.c
@@ -17,6 +17,7 @@
|
||||
#include<string.h>
|
||||
#include<stdio.h>
|
||||
#include<errno.h>
|
||||
#include<ifaddrs.h>
|
||||
|
||||
#define STUN_BINDING_REQUEST 0x0001
|
||||
#define STUN_BINDING_INDICATION 0x1100
|
||||
@@ -43,7 +44,7 @@ struct StunMsg {
|
||||
uint8_t id[12];
|
||||
};
|
||||
|
||||
static int stoon_init_mini(struct addrinfo *serv, uint16_t myport) {
|
||||
static int stoon_init_mini(struct Stoon *this, struct addrinfo *serv, uint16_t myport) {
|
||||
#ifdef _WIN32
|
||||
errno = 0;
|
||||
int fd = socket(serv->ai_family, serv->ai_socktype, serv->ai_protocol);
|
||||
@@ -59,16 +60,71 @@ static int stoon_init_mini(struct addrinfo *serv, uint16_t myport) {
|
||||
char p[6];
|
||||
sprintf(p, "%u", myport);
|
||||
|
||||
struct addrinfo *myaddr;
|
||||
if(getaddrinfo(NULL, p, &(struct addrinfo) {.ai_family = serv->ai_family, .ai_socktype = SOCK_DGRAM, .ai_protocol = IPPROTO_UDP, .ai_flags = AI_PASSIVE}, &myaddr)) {
|
||||
struct addrinfo *myaddrinfo;
|
||||
if(getaddrinfo(NULL, p, &(struct addrinfo) {.ai_family = serv->ai_family, .ai_socktype = SOCK_DGRAM, .ai_protocol = IPPROTO_UDP, .ai_flags = AI_PASSIVE}, &myaddrinfo)) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
if(bind(fd, myaddr->ai_addr, myaddr->ai_addrlen)) {
|
||||
if(bind(fd, myaddrinfo->ai_addr, myaddrinfo->ai_addrlen)) {
|
||||
close(fd);
|
||||
return -2;
|
||||
}
|
||||
freeaddrinfo(myaddr);
|
||||
|
||||
freeaddrinfo(myaddrinfo);
|
||||
|
||||
#ifdef _WIN32
|
||||
IP_ADAPTER_ADDRESSES *addrs = malloc(1024 * 64);
|
||||
if(GetAdaptersAddresses(serv->ai_family, GAA_FLAG_SKIP_MULTICAST, NULL, &addrs) == NO_ERROR) {
|
||||
for(IP_ADAPTER_ADDRESSES *ifa = addrs; ifa; ifa = ifa->Next) {
|
||||
if(serv->ai_family == AF_INET6) {
|
||||
uint8_t *addr = (void*) &((struct sockaddr_in6*) ifa->FirstUnicastAddress->Address.lpSockaddr)->sin6_addr;
|
||||
if(addr[0] == 0 && addr[1] == 0 && addr[2] == 0 && addr[3] == 0 && addr[4] == 0 && addr[5] == 0 && addr[6] == 0 && addr[7] == 0 && addr[8] == 0 && addr[9] == 0 && addr[10] == 0 && addr[11] == 0 && addr[12] == 0 && addr[13] == 0 && addr[14] == 0 && (addr[15] == 0 || addr[15] == 1)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(this->peercode.localV6, addr, 16);
|
||||
memcpy(this->peercode.localP6, &myport, 2);
|
||||
} else {
|
||||
uint8_t *addr = (void*) &((struct sockaddr_in*) ifa->FirstUnicastAddress->Address.lpSockaddr)->sin_addr;
|
||||
if(addr[0] == 0 && addr[1] == 0 && addr[2] == 0 && addr[3] == 0 || addr[0] == 127 && addr[1] == 0 && addr[2] == 0 && addr[3] == 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(this->peercode.localV4, addr, 4);
|
||||
memcpy(this->peercode.localP4, &myport, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(addrs);
|
||||
#else
|
||||
struct ifaddrs *ifaddr;
|
||||
if(getifaddrs(&ifaddr) >= 0) {
|
||||
for(struct ifaddrs *ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
|
||||
if(ifa->ifa_addr->sa_family == serv->ai_family) {
|
||||
if(serv->ai_family == AF_INET6) {
|
||||
uint8_t *addr = (void*) &((struct sockaddr_in6*) ifa->ifa_addr)->sin6_addr;
|
||||
if(addr[0] == 0 && addr[1] == 0 && addr[2] == 0 && addr[3] == 0 && addr[4] == 0 && addr[5] == 0 && addr[6] == 0 && addr[7] == 0 && addr[8] == 0 && addr[9] == 0 && addr[10] == 0 && addr[11] == 0 && addr[12] == 0 && addr[13] == 0 && addr[14] == 0 && (addr[15] == 0 || addr[15] == 1)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(this->peercode.localV6, addr, 16);
|
||||
memcpy(this->peercode.localP6, &myport, 2);
|
||||
} else {
|
||||
uint8_t *addr = (void*) &((struct sockaddr_in*) ifa->ifa_addr)->sin_addr;
|
||||
if(addr[0] == 0 && addr[1] == 0 && addr[2] == 0 && addr[3] == 0 || addr[0] == 127 && addr[1] == 0 && addr[2] == 0 && addr[3] == 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(this->peercode.localV4, addr, 4);
|
||||
memcpy(this->peercode.localP4, &myport, 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs(ifaddr);
|
||||
}
|
||||
#endif
|
||||
|
||||
return fd;
|
||||
}
|
||||
@@ -92,18 +148,16 @@ struct Stoon stoon_init(const char *stunhost, uint16_t stunport, uint16_t myport
|
||||
}
|
||||
}
|
||||
|
||||
struct Stoon ret;
|
||||
struct Stoon ret = {};
|
||||
|
||||
memset(&ret.my4, 0, sizeof(ret.my4));
|
||||
if(v4) {
|
||||
memcpy(&ret.stu4, v4->ai_addr, v4->ai_addrlen);
|
||||
ret.fd4 = stoon_init_mini(v4, myport);
|
||||
ret.fd4 = stoon_init_mini(&ret, v4, myport);
|
||||
} else ret.fd4 = -1;
|
||||
|
||||
memset(&ret.my6, 0, sizeof(ret.my6));
|
||||
if(v6) {
|
||||
memcpy(&ret.stu6, v6->ai_addr, v6->ai_addrlen);
|
||||
ret.fd6 = stoon_init_mini(v6, myport);
|
||||
ret.fd6 = stoon_init_mini(&ret, v6, myport);
|
||||
} else ret.fd6 = -1;
|
||||
|
||||
ret.poonchstage = 0;
|
||||
@@ -121,12 +175,21 @@ static int stoon_req_mini(struct Stoon *this, int *fd, struct sockaddr *serv, in
|
||||
if(errno == ENETUNREACH) {
|
||||
close(*fd);
|
||||
*fd = -1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
int stoon_req(struct Stoon *this) {
|
||||
if(this->fd4 >= 0) stoon_req_mini(this, &this->fd4, (struct sockaddr*) &this->stu4, sizeof(struct sockaddr_in));
|
||||
if(this->fd6 >= 0) stoon_req_mini(this, &this->fd6, (struct sockaddr*) &this->stu6, sizeof(struct sockaddr_in6));
|
||||
|
||||
if(this->fd4 < 0 && this->fd6 < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int stoon_listen_mini(struct Stoon *this, int fd, struct sockaddr *serv, int servlen) {
|
||||
@@ -161,11 +224,10 @@ static int stoon_listen_mini(struct Stoon *this, int fd, struct sockaddr *serv,
|
||||
uint16_t netfam = ntohs(((uint16_t*) d)[2]);
|
||||
uint16_t publicPort = ntohs(((uint16_t*) d)[3]) ^ (STUN_MAGIC >> 16);
|
||||
if(netfam == STUN_NETFAM_IPV4) {
|
||||
uint32_t publicIp = ntohl(((uint32_t*) d)[2]) ^ STUN_MAGIC;
|
||||
uint32_t publicIp = htonl(ntohl(((uint32_t*) d)[2]) ^ STUN_MAGIC);
|
||||
|
||||
this->my4.sin_family = AF_INET;
|
||||
memcpy(&this->my4.sin_addr, &publicIp, 4);
|
||||
this->my4.sin_port = htons(publicPort);
|
||||
memcpy(this->peercode.publicV4, &publicIp, 4);
|
||||
memcpy(this->peercode.publicP4, &publicPort, 2);
|
||||
|
||||
return 1;
|
||||
} else if(netfam == STUN_NETFAM_IPV6) {
|
||||
@@ -175,9 +237,8 @@ static int stoon_listen_mini(struct Stoon *this, int fd, struct sockaddr *serv,
|
||||
publicIp[2] = ((uint32_t*) d)[4] ^ ((uint32_t*) res.base.id)[1];
|
||||
publicIp[3] = ((uint32_t*) d)[5] ^ ((uint32_t*) res.base.id)[2];
|
||||
|
||||
this->my6.sin6_family = AF_INET6;
|
||||
memcpy(&this->my6.sin6_addr, &publicIp, 16);
|
||||
this->my6.sin6_port = htons(publicPort);
|
||||
memcpy(this->peercode.publicV6, &publicIp, 16);
|
||||
memcpy(this->peercode.publicP6, &publicPort, 2);
|
||||
|
||||
return 1;
|
||||
} else {
|
||||
@@ -188,12 +249,12 @@ static int stoon_listen_mini(struct Stoon *this, int fd, struct sockaddr *serv,
|
||||
d += 4 + attribLen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
int stoon_listen(struct Stoon *this) {
|
||||
if(this->fd4 >= 0) if(stoon_listen_mini(this, this->fd4, (struct sockaddr*) &this->stu4, sizeof(struct sockaddr_in)) < 0) return 0;
|
||||
if(this->fd6 >= 0) if(stoon_listen_mini(this, this->fd6, (struct sockaddr*) &this->stu6, sizeof(struct sockaddr_in6)) < 0) return 0;
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
void stoon_keepalive(struct Stoon *this) {
|
||||
@@ -217,31 +278,7 @@ void stoon_kill(struct Stoon *this) {
|
||||
this->fd6 = -1;
|
||||
}
|
||||
|
||||
int stoon_v4_available(struct Stoon *this) {
|
||||
return this->fd4 >= 0;
|
||||
}
|
||||
|
||||
int stoon_v6_available(struct Stoon *this) {
|
||||
return this->fd6 >= 0;
|
||||
}
|
||||
|
||||
void stoon_serialize(struct Stoon *this, uint8_t ret[static STOON_CONN_INFO_SIZE]) {
|
||||
if(this->fd4 >= 0) {
|
||||
memcpy(ret + 0, &this->my4.sin_addr, 4);
|
||||
memcpy(ret + 4, &this->my4.sin_port, 2);
|
||||
} else {
|
||||
memset(ret, 0, 6);
|
||||
}
|
||||
|
||||
if(this->fd6 >= 0) {
|
||||
memcpy(ret + 6, &this->my6.sin6_addr, 16);
|
||||
memcpy(ret + 22, &this->my6.sin6_port, 2);
|
||||
} else {
|
||||
memset(ret + 6, 0, 18);
|
||||
}
|
||||
}
|
||||
|
||||
int stoon_poonch(struct Stoon *this, const uint8_t peerdata[static STOON_CONN_INFO_SIZE]) {
|
||||
/*int stoon_poonch(struct Stoon *this, const uint8_t peerdata[static STOON_CONN_INFO_SIZE]) {
|
||||
struct {
|
||||
uint32_t addr4;
|
||||
uint16_t port4;
|
||||
@@ -303,7 +340,7 @@ int stoon_poonch(struct Stoon *this, const uint8_t peerdata[static STOON_CONN_IN
|
||||
}
|
||||
|
||||
return STOON_POONCH_NO_KNOCK;
|
||||
}
|
||||
}*/
|
||||
|
||||
#ifdef STOON_STANDALONE
|
||||
int main() {
|
||||
|
||||
Reference in New Issue
Block a user