diff --git a/src/sniffer.c b/src/sniffer.c index 60cbb1791..8fd3531e0 100644 --- a/src/sniffer.c +++ b/src/sniffer.c @@ -78,6 +78,7 @@ enum { IP_HDR_SZ = 20, /* IP header length, min */ TCP_HDR_SZ = 20, /* TCP header length, min */ IPV4 = 4, /* IP version 4 */ + IPV6 = 6, /* IP version 6 */ TCP_PROTOCOL = 6, /* TCP Protocol id */ TRACE_MSG_SZ = 80, /* Trace Message buffer size */ HASH_SIZE = 499, /* Session Hash Table Rows */ @@ -316,11 +317,18 @@ typedef struct NamedKey { #endif +typedef union IpAddrInfo { + word32 ip4; + word32 ip6[4]; +} IpAddrInfo; + + /* Sniffer Server holds info for each server/port monitored */ typedef struct SnifferServer { SSL_CTX* ctx; /* SSL context */ char address[MAX_SERVER_ADDRESS]; /* passed in server address */ - word32 server; /* netowrk order address */ + IpAddrInfo server; /* network order address */ + int version; /* IP version */ int port; /* server port */ #ifdef HAVE_SNI NamedKey* namedKeys; /* mapping of names and keys */ @@ -382,8 +390,9 @@ typedef struct SnifferSession { SnifferServer* context; /* server context */ SSL* sslServer; /* SSL server side decode */ SSL* sslClient; /* SSL client side decode */ - word32 server; /* server address in network byte order */ - word32 client; /* client address in network byte order */ + IpAddrInfo server; /* server address in network byte order */ + IpAddrInfo client; /* client address in network byte order */ + int version; word16 srvPort; /* server port */ word16 cliPort; /* client port */ word32 cliSeqStart; /* client start sequence */ @@ -744,85 +753,40 @@ static int HashCopy(HS_Hashes* d, HsHashes* s) /* Initialize a SnifferServer */ static void InitSnifferServer(SnifferServer* sniffer) { - sniffer->ctx = 0; - XMEMSET(sniffer->address, 0, MAX_SERVER_ADDRESS); - sniffer->server = 0; - sniffer->port = 0; -#ifdef HAVE_SNI - sniffer->namedKeys = 0; - wc_InitMutex(&sniffer->namedKeysMutex); -#endif - sniffer->next = 0; + XMEMSET(sniffer, 0, sizeof(SnifferServer)); } /* Initialize session flags */ static void InitFlags(Flags* flags) { - flags->side = 0; - flags->serverCipherOn = 0; - flags->clientCipherOn = 0; - flags->resuming = 0; - flags->cached = 0; - flags->clientHello = 0; - flags->finCount = 0; - flags->fatalError = 0; - flags->cliAckFault = 0; - flags->srvAckFault = 0; - flags->cliSkipPartial = 0; - flags->srvSkipPartial = 0; -#ifdef HAVE_EXTENDED_MASTER - flags->expectEms = 0; -#endif + XMEMSET(flags, 0, sizeof(Flags)); } /* Initialize FIN Capture */ static void InitFinCapture(FinCaputre* cap) { - cap->cliFinSeq = 0; - cap->srvFinSeq = 0; - cap->cliCounted = 0; - cap->srvCounted = 0; + XMEMSET(cap, 0, sizeof(FinCaputre)); } /* Initialize a Sniffer Session */ static void InitSession(SnifferSession* session) { - session->context = 0; - session->sslServer = 0; - session->sslClient = 0; - session->server = 0; - session->client = 0; - session->srvPort = 0; - session->cliPort = 0; - session->cliSeqStart = 0; - session->srvSeqStart = 0; - session->cliExpected = 0; - session->srvExpected = 0; - session->lastUsed = 0; - session->cliReassemblyList = 0; - session->srvReassemblyList = 0; - session->cliReassemblyMemory = 0; - session->srvReassemblyMemory = 0; - session->next = 0; - session->ticketID = 0; - + XMEMSET(session, 0, sizeof(SnifferSession)); InitFlags(&session->flags); InitFinCapture(&session->finCaputre); -#ifdef HAVE_EXTENDED_MASTER - session->hash = 0; -#endif } /* IP Info from IP Header */ typedef struct IpInfo { + int version; /* IP version */ int length; /* length of this header */ int total; /* total length of fragment */ - word32 src; /* network order source address */ - word32 dst; /* network order destination address */ + IpAddrInfo src; /* network order source address */ + IpAddrInfo dst; /* network order destination address */ } IpInfo; @@ -868,7 +832,7 @@ typedef struct EthernetHdr { } EthernetHdr; -/* IP Header */ +/* IPv4 Header */ typedef struct IpHdr { byte ver_hl; /* version/header length */ byte tos; /* type of service */ @@ -883,6 +847,19 @@ typedef struct IpHdr { } IpHdr; +/* IPv6 Header */ +typedef struct Ip6Hdr { + byte ver_hl; /* version/traffic class high */ + byte tc_fl; /* traffic class low/flow label high */ + word16 fl; /* flow label low */ + word16 length; /* payload length */ + byte next_header; /* next header (6 for TCP, any other skip) */ + byte hl; /* hop limit */ + word32 src[4]; /* source address */ + word32 dst[4]; /* destination address */ +} Ip6Hdr; + + #define IP_HL(ip) ( (((ip)->ver_hl) & 0x0f) * 4) #define IP_V(ip) ( ((ip)->ver_hl) >> 4) @@ -982,6 +959,18 @@ static char* IpToS(word32 addr, char* str) } +/* Convert network byte order address into human readable */ +static char* Ip6ToS(word32* addr, char* str) +{ + byte* p = (byte*)addr; + + /* Very incorrect. XXX */ + SNPRINTF(str, TRACE_MSG_SZ, "::%d", p[127]); + + return str; +} + + /* Show destination and source address from Ip Hdr for packet Trace */ static void TraceIP(IpHdr* iphdr) { @@ -994,6 +983,18 @@ static void TraceIP(IpHdr* iphdr) } +/* Show destination and source address from Ip6Hdr for packet Trace */ +static void TraceIP6(Ip6Hdr* iphdr) +{ + if (TraceOn) { + char src[TRACE_MSG_SZ]; + char dst[TRACE_MSG_SZ]; + fprintf(TraceFile, "\tdst:%s src:%s\n", Ip6ToS(iphdr->dst, dst), + Ip6ToS(iphdr->src, src)); + } +} + + /* Show destination and source port from Tcp Hdr for packet Trace */ static void TraceTcp(TcpHdr* tcphdr) { @@ -1178,7 +1179,32 @@ static int IsServerRegistered(word32 addr) sniffer = ServerList; while (sniffer) { - if (sniffer->server == addr) { + if (sniffer->server.ip4 == addr) { + ret = 1; + break; + } + sniffer = sniffer->next; + } + + wc_UnLockMutex(&ServerListMutex); + + return ret; +} + + +/* See if this port has been registered to watch */ +/* See if this IPV4 network order address has been registered */ +/* return 1 is true, 0 is false */ +static int IsServerRegistered6(word32* addr) +{ + int ret = 0; /* false */ + SnifferServer* sniffer; + + wc_LockMutex(&ServerListMutex); + + sniffer = ServerList; + while (sniffer) { + if (XMEMCMP(sniffer->server.ip6, addr, sizeof(sniffer->server.ip6))) { ret = 1; break; } @@ -1228,10 +1254,25 @@ static SnifferServer* GetSnifferServer(IpInfo* ipInfo, TcpInfo* tcpInfo) #ifndef WOLFSSL_SNIFFER_WATCH while (sniffer) { - if (sniffer->port == tcpInfo->srcPort && sniffer->server == ipInfo->src) - break; - if (sniffer->port == tcpInfo->dstPort && sniffer->server == ipInfo->dst) - break; + if (ipInfo->version == IPV4) { + if (sniffer->port == tcpInfo->srcPort && + sniffer->server.ip4 == ipInfo->src.ip4) + break; + if (sniffer->port == tcpInfo->dstPort && + sniffer->server.ip4 == ipInfo->dst.ip4) + break; + } + else if (ipInfo->version == IPV6) { + if (sniffer->port == tcpInfo->srcPort && + XMEMCMP(sniffer->server.ip6, ipInfo->src.ip6, + sizeof(sniffer->server.ip6)) == 0) + break; + if (sniffer->port == tcpInfo->dstPort && + XMEMCMP(sniffer->server.ip6, ipInfo->dst.ip6, + sizeof(sniffer->server.ip6)) == 0) + break; + } + sniffer = sniffer->next; } #else @@ -1248,13 +1289,35 @@ static SnifferServer* GetSnifferServer(IpInfo* ipInfo, TcpInfo* tcpInfo) /* Hash the Session Info, return hash row */ static word32 SessionHash(IpInfo* ipInfo, TcpInfo* tcpInfo) { - word32 hash = ipInfo->src * ipInfo->dst; + word32 hash = 1; + + if (ipInfo->version == IPV4) { + hash *= ipInfo->src.ip4 * ipInfo->dst.ip4; + } + else if (ipInfo->version == IPV6) { + word32 x; + x = ipInfo->src.ip6[0] ^ ipInfo->src.ip6[1] ^ + ipInfo->src.ip6[2] ^ ipInfo->src.ip6[3]; + hash *= x; + x = ipInfo->dst.ip6[0] ^ ipInfo->dst.ip6[1] ^ + ipInfo->dst.ip6[2] ^ ipInfo->dst.ip6[3]; + hash *= x; + } hash *= tcpInfo->srcPort * tcpInfo->dstPort; return hash % HASH_SIZE; } +static inline int MatchAddr(int version, IpAddrInfo l, IpAddrInfo r) +{ + if (version == IPV4) + return (l.ip4 == r.ip4); + else + return (0 == XMEMCMP(l.ip6, r.ip6, sizeof(l.ip6))); +} + + /* Get Exisiting SnifferSession from IP and Port */ static SnifferSession* GetSnifferSession(IpInfo* ipInfo, TcpInfo* tcpInfo) { @@ -1268,11 +1331,14 @@ static SnifferSession* GetSnifferSession(IpInfo* ipInfo, TcpInfo* tcpInfo) session = SessionTable[row]; while (session) { - if (session->server == ipInfo->src && session->client == ipInfo->dst && + if (MatchAddr(session->version, session->server, ipInfo->src) && + MatchAddr(session->version, session->client, ipInfo->dst) && session->srvPort == tcpInfo->srcPort && session->cliPort == tcpInfo->dstPort) break; - if (session->client == ipInfo->src && session->server == ipInfo->dst && + + if (MatchAddr(session->version, session->client, ipInfo->src) && + MatchAddr(session->version, session->server, ipInfo->dst) && session->cliPort == tcpInfo->srcPort && session->srvPort == tcpInfo->dstPort) break; @@ -1287,11 +1353,14 @@ static SnifferSession* GetSnifferSession(IpInfo* ipInfo, TcpInfo* tcpInfo) /* determine side */ if (session) { - if (ipInfo->dst == session->server && - tcpInfo->dstPort == session->srvPort) + if (MatchAddr(ipInfo->version, ipInfo->dst, session->server) && + tcpInfo->dstPort == session->srvPort) { + session->flags.side = WOLFSSL_SERVER_END; - else + } + else { session->flags.side = WOLFSSL_CLIENT_END; + } } return session; @@ -1449,7 +1518,7 @@ static int SetNamedPrivateKey(const char* name, const char* address, int port, serverIp = inet_addr(address); sniffer = ServerList; while (sniffer != NULL && - (sniffer->server != serverIp || sniffer->port != port)) { + (sniffer->server.ip4 != serverIp || sniffer->port != port)) { sniffer = sniffer->next; } @@ -1468,7 +1537,7 @@ static int SetNamedPrivateKey(const char* name, const char* address, int port, XSTRNCPY(sniffer->address, address, MAX_SERVER_ADDRESS-1); sniffer->address[MAX_SERVER_ADDRESS-1] = '\0'; - sniffer->server = serverIp; + sniffer->server.ip4 = serverIp; sniffer->port = port; sniffer->ctx = SSL_CTX_new(TLSv1_2_client_method()); @@ -1569,7 +1638,49 @@ int ssl_SetPrivateKey(const char* address, int port, const char* keyFile, } +/* Check IP Header for IPV6, TCP, and a registered server address */ +/* returns 0 on success, -1 on error */ +static int CheckIp6Hdr(Ip6Hdr* iphdr, IpInfo* info, int length, char* error) +{ + int version = IP_V(iphdr); + + TraceIP6(iphdr); + Trace(IP_CHECK_STR); + + if (version != IPV6) { + SetError(BAD_IPVER_STR, error, NULL, 0); + return -1; + } + + /* Here, we need to move onto next header if not TCP. */ + if (iphdr->next_header != TCP_PROTOCOL) { + SetError(BAD_PROTO_STR, error, NULL, 0); + return -1; + } + +#ifndef WOLFSSL_SNIFFER_WATCH + if (!IsServerRegistered6(iphdr->src) && !IsServerRegistered6(iphdr->dst)) { + SetError(SERVER_NOT_REG_STR, error, NULL, 0); + return -1; + } +#endif + + info->total = ntohs(iphdr->length); + info->version = IPV6; + XMEMCPY(info->src.ip6, iphdr->src, sizeof(info->src.ip6)); + XMEMCPY(info->dst.ip6, iphdr->src, sizeof(info->dst.ip6)); + + /* This needs to massage the length and size to match what the sniffer + * expects. IPv4 and IPv6 treat the length parameter differently. */ + if (info->total == 0) + info->total = length; /* reassembled may be off */ + + return 0; +} + + /* Check IP Header for IPV4, TCP, and a registered server address */ +/* If header IPv6, pass to CheckIp6Hdr(). */ /* returns 0 on success, -1 on error */ static int CheckIpHdr(IpHdr* iphdr, IpInfo* info, int length, char* error) { @@ -1578,6 +1689,9 @@ static int CheckIpHdr(IpHdr* iphdr, IpInfo* info, int length, char* error) TraceIP(iphdr); Trace(IP_CHECK_STR); + if (version == IPV6) + return CheckIp6Hdr((Ip6Hdr*)iphdr, info, length, error); + if (version != IPV4) { SetError(BAD_IPVER_STR, error, NULL, 0); return -1; @@ -1597,8 +1711,9 @@ static int CheckIpHdr(IpHdr* iphdr, IpInfo* info, int length, char* error) info->length = IP_HL(iphdr); info->total = ntohs(iphdr->length); - info->src = iphdr->src; - info->dst = iphdr->dst; + info->version = IPV4; + info->src.ip4 = iphdr->src; + info->dst.ip4 = iphdr->dst; if (info->total == 0) info->total = length; /* reassembled may be off */