diff --git a/src/apps/relay/ns_ioalib_engine_impl.c b/src/apps/relay/ns_ioalib_engine_impl.c index ba1e387f..2eb1b30b 100644 --- a/src/apps/relay/ns_ioalib_engine_impl.c +++ b/src/apps/relay/ns_ioalib_engine_impl.c @@ -2166,6 +2166,101 @@ static TURN_TLS_TYPE check_tentative_tls(ioa_socket_raw fd) } #endif + +static size_t proxy_string_field(char *field, size_t max, uint8_t *buf, size_t index, size_t len) +{ + size_t count = 0; + while((index < len) && (count < max)) { + if((0x20 == buf[index]) || (0x0D == buf[index])) { + field[count] = 0x00; + return ++index; + } + field[count++] = buf[index++]; + } + return 0; +} + +static ssize_t socket_parse_proxy_v1(ioa_socket_handle s, uint8_t *buf, size_t len) +{ + if(len < 11) { + return 0 ; + } + + /* Check for proxy-v1 magic field */ + char magic[] = {0x50, 0x52, 0x4F, 0x58, 0x59, 0x20}; + if(memcmp(magic, buf, sizeof(magic))) { + return -1; + } + + /* Read family */ + char tcp4[] = {0x54, 0x43, 0x50, 0x34, 0x20}; + char tcp6[] = {0x54, 0x43, 0x50, 0x36, 0x20}; + int family; + if(0 == memcmp(tcp4, &buf[6], sizeof(tcp4))) { /* IPv4 */ + family = AF_INET; + } else if(0 == memcmp(tcp6, &buf[6], sizeof(tcp6))) { /* IPv6 */ + family = AF_INET6; + } else { + return -1; + } + + char saddr[40]; + char daddr[40]; + char sport[6]; + char dport[6]; + + size_t tlen = 11; + /* Read source address */ + tlen = proxy_string_field(saddr, sizeof(saddr), buf, tlen, len); + if(0 == tlen) return -1; + + /* Read dest address */ + tlen = proxy_string_field(daddr, sizeof(daddr), buf, tlen, len); + if(0 == tlen) return -1; + + /* Read source port */ + tlen = proxy_string_field(sport, sizeof(sport), buf, tlen, len); + if(0 == tlen) return -1; + + /* Read dest port */ + tlen = proxy_string_field(dport, sizeof(dport), buf, tlen, len); + if(0 == tlen) return -1; + + /* Final line feed */ + if ((len <= tlen) || (0x0A != buf[tlen])) return -1; + + tlen++; + + int sport_int = atoi(sport); + int dport_int = atoi(dport); + if((sport_int < 0) || (0xFFFF < sport_int)) return -1; + if((dport_int < 0) || (0xFFFF < dport_int)) return -1; + + if (AF_INET == family) { + struct sockaddr_in remote, local; + remote.sin_family = local.sin_family = AF_INET; + if(1 != inet_pton(AF_INET, saddr, &remote.sin_addr.s_addr)) return -1; + if(1 != inet_pton(AF_INET, daddr, &local.sin_addr.s_addr)) return -1; + remote.sin_port = htons((uint16_t)sport_int); + local.sin_port = htons((uint16_t)dport_int); + + addr_cpy4(&(s->local_addr), &local); + addr_cpy4(&(s->remote_addr), &remote); + + } else { + struct sockaddr_in6 remote, local; + remote.sin6_family = local.sin6_family = AF_INET6; + if(1 != inet_pton(AF_INET6, saddr, &remote.sin6_addr.s6_addr)) return -1; + if(1 != inet_pton(AF_INET6, daddr, &local.sin6_addr.s6_addr)) return -1; + remote.sin6_port = htons((uint16_t)sport_int); + local.sin6_port = htons((uint16_t)dport_int); + + addr_cpy6(&(s->local_addr), &local); + addr_cpy6(&(s->remote_addr), &remote); + } + return tlen; +} + static ssize_t socket_parse_proxy_v2(ioa_socket_handle s, uint8_t *buf, size_t len) { if(len < 16){ @@ -2227,6 +2322,16 @@ static ssize_t socket_parse_proxy_v2(ioa_socket_handle s, uint8_t *buf, size_t l return tlen; } +static ssize_t socket_parse_proxy(ioa_socket_handle s, uint8_t *buf, size_t len) +{ + ssize_t tlen = socket_parse_proxy_v2(s, buf, len); + if(-1 == tlen) { + tlen = socket_parse_proxy_v1(s, buf, len); + } + + return tlen; +} + static int socket_input_worker(ioa_socket_handle s) { int len = 0; @@ -2450,7 +2555,7 @@ static int socket_input_worker(ioa_socket_handle s) blen=(ev_ssize_t)STUN_BUFFER_SIZE; if(s->st == TCP_SOCKET_PROXY){ - ssize_t tlen = socket_parse_proxy_v2(s, buf_elem->buf.buf, blen); + ssize_t tlen = socket_parse_proxy(s, buf_elem->buf.buf, blen); blen = 0; if (tlen < 0){ s->tobeclosed = 1;