diff options
Diffstat (limited to 'src/lib/protocols/stun.c')
-rw-r--r-- | src/lib/protocols/stun.c | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/src/lib/protocols/stun.c b/src/lib/protocols/stun.c new file mode 100644 index 000000000..09ec4a050 --- /dev/null +++ b/src/lib/protocols/stun.c @@ -0,0 +1,188 @@ +/* + * stun.c + * + * Copyright (C) 2009-2011 by ipoque GmbH + * Copyright (C) 2011-15 - ntop.org + * + * This file is part of nDPI, an open source deep packet inspection + * library based on the OpenDPI and PACE technology by ipoque GmbH + * + * nDPI is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * nDPI is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with nDPI. If not, see <http://www.gnu.org/licenses/>. + * + */ + + +#include "ndpi_protocols.h" +#ifdef NDPI_PROTOCOL_STUN + + +static void ndpi_int_stun_add_connection(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) +{ + ndpi_int_add_connection(ndpi_struct, flow, NDPI_PROTOCOL_STUN, NDPI_REAL_PROTOCOL); +} + + + +typedef enum { + NDPI_IS_STUN, + NDPI_IS_NOT_STUN +} ndpi_int_stun_t; + +static ndpi_int_stun_t ndpi_int_check_stun(struct ndpi_detection_module_struct *ndpi_struct, + const u_int8_t * payload, const u_int16_t payload_length) +{ + u_int16_t a; + + + if((payload_length > 13) + && (strncmp((const char*)payload, (const char*)"RSP/", 4) == 0) + && (strncmp((const char*)&payload[7], (const char*)" STUN_", 6) == 0)) { + NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "Found stun.\n"); + return NDPI_IS_STUN; + } + + /* + * token list of message types and attribute types from + * http://wwwbs1.informatik.htw-dresden.de/svortrag/i02/Schoene/stun/stun.html + * the same list you can find in + * https://summersoft.fay.ar.us/repos/ethereal/branches/redhat-9/ethereal-0.10.3-1/ethereal-0.10.3/packet-stun.c + * token further message types and attributes from + * http://www.freeswitch.org/docs/group__stun1.html + * added further attributes observed + * message types: 0x0001, 0x0101, 0x0111, 0x0002, 0x0102, 0x0112, 0x0003, 0x0103, 0x0004, 0x0104, 0x0114, 0x0115 + * attribute types: 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, + * 0x000a, 0x000b, 0c000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0020, + * 0x0022, 0x0024, 0x8001, 0x8006, 0x8008, 0x8015, 0x8020, 0x8028, 0x802a, 0x8029, 0x8050, 0x8054, 0x8055 + * + * 0x8003, 0x8004 used by facetime + */ + + if (payload_length >= 20 && ntohs(get_u_int16_t(payload, 2)) + 20 == payload_length && + ((payload[0] == 0x00 && (payload[1] >= 0x01 && payload[1] <= 0x04)) || + (payload[0] == 0x01 && + ((payload[1] >= 0x01 && payload[1] <= 0x04) || (payload[1] >= 0x11 && payload[1] <= 0x15))))) { + u_int8_t mod; + u_int8_t old = 1; + u_int8_t padding = 0; + NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "len and type match.\n"); + + if (payload_length == 20) { + NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "found stun.\n"); + return NDPI_IS_STUN; + } + + a = 20; + + while (a < payload_length) { + + if (old && payload_length >= a + 4 + && + ((payload[a] == 0x00 + && ((payload[a + 1] >= 0x01 && payload[a + 1] <= 0x16) || payload[a + 1] == 0x19 + || payload[a + 1] == 0x20 || payload[a + 1] == 0x22 || payload[a + 1] == 0x24 + || payload[a + 1] == 0x25)) + || (payload[a] == 0x80 + && (payload[a + 1] == 0x01 || payload[a + 1] == 0x03 || payload[a + 1] == 0x04 + || payload[a + 1] == 0x06 || payload[a + 1] == 0x08 || payload[a + 1] == 0x15 + || payload[a + 1] == 0x20 || payload[a + 1] == 0x22 || payload[a + 1] == 0x28 + || payload[a + 1] == 0x2a || payload[a + 1] == 0x29 || payload[a + 1] == 0x50 + || payload[a + 1] == 0x54 || payload[a + 1] == 0x55)))) { + + NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "attribute match.\n"); + + a += ((payload[a + 2] << 8) + payload[a + 3] + 4); + mod = a % 4; + if (mod) { + padding = 4 - mod; + } + if (a == payload_length || (padding && (a + padding) == payload_length)) { + NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "found stun.\n"); + return NDPI_IS_STUN; + } + + } else if (payload_length >= a + padding + 4 + && + ((payload[a + padding] == 0x00 + && ((payload[a + 1 + padding] >= 0x01 && payload[a + 1 + padding] <= 0x16) + || payload[a + 1 + padding] == 0x19 || payload[a + 1 + padding] == 0x20 + || payload[a + 1 + padding] == 0x22 || payload[a + 1 + padding] == 0x24 + || payload[a + 1 + padding] == 0x25)) + || (payload[a + padding] == 0x80 + && (payload[a + 1 + padding] == 0x01 || payload[a + 1 + padding] == 0x03 + || payload[a + 1 + padding] == 0x04 || payload[a + 1 + padding] == 0x06 + || payload[a + 1 + padding] == 0x08 || payload[a + 1 + padding] == 0x15 + || payload[a + 1 + padding] == 0x20 || payload[a + 1 + padding] == 0x22 + || payload[a + 1 + padding] == 0x28 || payload[a + 1 + padding] == 0x2a + || payload[a + 1 + padding] == 0x29 || payload[a + 1 + padding] == 0x50 + || payload[a + 1 + padding] == 0x54 || payload[a + 1 + padding] == 0x55)))) { + + NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "New STUN - attribute match.\n"); + + old = 0; + a += ((payload[a + 2 + padding] << 8) + payload[a + 3 + padding] + 4); + padding = 0; + mod = a % 4; + if (mod) { + a += 4 - mod; + } + if (a == payload_length) { + NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "found stun.\n"); + return NDPI_IS_STUN; + } + } else { + break; + } + } + } + + return NDPI_IS_NOT_STUN; +} + +void ndpi_search_stun(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) +{ + struct ndpi_packet_struct *packet = &flow->packet; + + + NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "search stun.\n"); + + + if (packet->tcp) { + + /* STUN may be encapsulated in TCP packets */ + + if (packet->payload_packet_len >= 2 + 20 && + ntohs(get_u_int16_t(packet->payload, 0)) + 2 == packet->payload_packet_len) { + + /* TODO there could be several STUN packets in a single TCP packet so maybe the detection could be + * improved by checking only the STUN packet of given length */ + + if (ndpi_int_check_stun(ndpi_struct, packet->payload + 2, packet->payload_packet_len - 2) == + NDPI_IS_STUN) { + NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "found TCP stun.\n"); + ndpi_int_stun_add_connection(ndpi_struct, flow); + return; + } + } + } + if (ndpi_int_check_stun(ndpi_struct, packet->payload, packet->payload_packet_len) == NDPI_IS_STUN) { + NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "found UDP stun.\n"); + ndpi_int_stun_add_connection(ndpi_struct, flow); + return; + } + + NDPI_LOG(NDPI_PROTOCOL_STUN, ndpi_struct, NDPI_LOG_DEBUG, "exclude stun.\n"); + NDPI_ADD_PROTOCOL_TO_BITMASK(flow->excluded_protocol_bitmask, NDPI_PROTOCOL_STUN); +} + +#endif |