/* * Copyright 2001 Niels Provos * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Niels Provos. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef BSD #include #endif #include #include "buffer.h" #include "g711.h" #include "voip.h" #define MAXTALKS 2 #define MAXSAMPLES 480 #define MAXBUFFER (10000*MAXSAMPLES) extern int lnet_sock; extern int pcap_off; extern int debug; int16_t lastidnr = 0; /* XXX - Seen cache */ ip_addr_t tcp_src; ip_addr_t tcp_dst; u_int32_t tcp_seqnr; /* XXX - bad */ char phone_number[1024]; u_char voip_magic_data[2] = {0x80, 0x00}; u_char voip_magic_start[2] = {0x80, 0x80}; extern struct event voipev; /* buffer handler */ bh bhd; /* Evil - we'll just voip_session = bufid */ struct voip_session { struct in_addr src; struct in_addr dst; u_short sport; u_short dport; u_int32_t magic; }; int voip_seen(struct ip_hdr *ip, struct tcp_hdr *tcp) { if (ip->ip_src == tcp_src && ip->ip_dst == tcp_dst && tcp->th_seq == tcp_seqnr) return (1); tcp_src = ip->ip_src; tcp_dst = ip->ip_dst; tcp_seqnr = tcp->th_seq; return (0); } void voip_init(void) { bhd = buffer_new(MAXTALKS, MAXSAMPLES, MAXBUFFER); buffer_init(bhd); } void make_ident(ip_addr_t *src, u_short sport, ip_addr_t *dst, u_short dport, u_int32_t magic, bufid *pident) { u_char *ident = (u_char *)pident; memset(ident, 0, sizeof(ident)); memcpy(ident, src, sizeof(*src)); ident += sizeof(*src); memcpy(ident, dst, sizeof(*dst)); ident += sizeof(*dst); memcpy(ident, &sport, sizeof(sport)); ident += sizeof(sport); memcpy(ident, &dport, sizeof(dport)); ident += sizeof(dport); memcpy(ident, &magic, sizeof(magic)); ident += sizeof(magic); } void voip_sniff_tcp(u_char *user, const struct pcap_pkthdr *pkthdr, const u_char *pkt) { struct ip_hdr *ip; struct tcp_hdr *tcp; struct voip_signal *voip; struct addr src, dst; u_char *p; char *cmd, *what; char extra[1024]; char tmp[2]; int len; char srcname[MAXHOSTNAMELEN], dstname[MAXHOSTNAMELEN]; ip = (struct ip_hdr *)(pkt + pcap_off); tcp = (struct tcp_hdr *)(pkt + pcap_off + (ip->ip_hl<<2)); voip = (struct voip_signal *)(pkt + pcap_off + (ip->ip_hl<<2) + (tcp->th_off<<2)); p = (u_char *)(voip + 1); len = ntohs(ip->ip_len) - (ip->ip_hl<<2) - (tcp->th_off<<2); if (len < sizeof(struct voip_signal)) { if (debug) fprintf(stderr, "Bad packet length: %d\n", len); return; } if (voip_seen(ip, tcp)) return; addr_pack(&src, ADDR_TYPE_IP, IP_ADDR_BITS, &ip->ip_src, IP_ADDR_LEN); addr_pack(&dst, ADDR_TYPE_IP, IP_ADDR_BITS, &ip->ip_dst, IP_ADDR_LEN); strlcpy(srcname, addr_ntoa(&src), sizeof (srcname)); strlcpy(dstname, addr_ntoa(&dst), sizeof (dstname)); what = cmd = ""; extra[0] = '\0'; switch(voip->proto) { case VOIP_IE_CON: what = "Connection"; switch(voip->cmd) { case VOIP_CON_PICKUP: cmd = "Handset pick up"; phone_number[0] = '\0'; break; case VOIP_CON_HANGUP: cmd = "Handset hang up"; break; case VOIP_CON_ALIVE: if (!debug) return; cmd = "Keep Alive"; break; default: cmd = "Unknown command"; break; } break; case VOIP_IE_USER: what = "User Input"; switch (voip->cmd) { case VOIP_USER_DIAL: cmd = "Dial"; if (len == sizeof(struct voip_signal) + 4) { snprintf(extra, sizeof(extra), "(Digit %d)", p[0]); } tmp[0] = p[0] + '0'; tmp[1] = '\0'; strlcat(phone_number, tmp, sizeof (phone_number)); } break; case VOIP_IE_DISPLAY: what = "Display"; switch (voip->cmd) { case VOIP_DISPLAY_STATUS: cmd = "Status"; if (len <= sizeof(struct voip_signal)) break; len -= sizeof(struct voip_signal); if (len < voip->plen) break; snprintf(extra, sizeof(extra), "\n\t(%s)", (char *)p); break; default: cmd = "Unknown"; break; } break; default: what = "unknown"; cmd = "unknown"; break; } fprintf(stderr, "%s -> %s: %s(0x%x) %s(0x%x) %s\n", srcname, dstname, what, voip->proto, cmd, voip->cmd, extra); } void voip_sniff_udp(u_char *user, const struct pcap_pkthdr *pkthdr, const u_char *pkt) { struct ip_hdr *ip; struct udp_hdr *udp; struct voip_hdr *voip; bufid ident; char srcname[MAXHOSTNAMELEN], dstname[MAXHOSTNAMELEN]; u_char *p; u_int16_t buf[1024]; int i, len; ip = (struct ip_hdr *)(pkt + pcap_off); udp = (struct udp_hdr *)(pkt + pcap_off + (ip->ip_hl<<2)); voip = (struct voip_hdr *)(udp + 1); p = (u_char *)(voip + 1); len = ntohs(udp->uh_ulen) - sizeof(struct udp_hdr); if (len < sizeof (struct voip_hdr)) { if (debug > 1) fprintf(stderr, "Bad packet: Len %d\n", len); return; } voip->id = ntohs(voip->id); voip->seqnr = ntohl(voip->seqnr); if (memcmp(voip_magic_data, voip->magic, sizeof(voip_magic_data))) { if (memcmp(voip_magic_start, voip->magic, sizeof(voip_magic_start))) { if (debug > 1) fprintf(stderr, "Bad packet: Magic: %02x %02x\n", voip->magic[0], voip->magic[1]); return; } if (lastidnr != voip->id) { struct addr src, dst; lastidnr = voip->id; addr_pack(&src, ADDR_TYPE_IP, IP_ADDR_BITS, &ip->ip_src, IP_ADDR_LEN); addr_pack(&dst, ADDR_TYPE_IP, IP_ADDR_BITS, &ip->ip_dst, IP_ADDR_LEN); strlcpy(srcname, addr_ntoa(&src), sizeof (srcname)); strlcpy(dstname, addr_ntoa(&dst), sizeof (dstname)); fprintf(stderr, "Client: %s -> %s:\n" "\tid %d, seqnr: %u, 0x%0x\n" "\tDialed number: %s\n", srcname, dstname, voip->id, voip->seqnr, ntohl(voip->magicnr), phone_number); buffer_clear(bhd); } } len -= sizeof (struct voip_hdr); for (i = 0; i < len; i++) { buf[i] = ulaw2linear(p[i]); } make_ident(&ip->ip_src, udp->uh_sport, &ip->ip_dst, udp->uh_dport, voip->magicnr, &ident); buffer_enqueue(bhd, &ident, voip->id, voip->seqnr, buf, len); return; } void voip_sniff(u_char *user, const struct pcap_pkthdr *pkthdr, const u_char *pkt) { struct ip_hdr *ip; ip = (struct ip_hdr *)(pkt + pcap_off); switch(ip->ip_p) { case IPPROTO_UDP: voip_sniff_udp(user, pkthdr, pkt); break; case IPPROTO_TCP: voip_sniff_tcp(user, pkthdr, pkt); break; default: break; } }