void echo_discard_start (void) { #if defined(USE_DEBUG) char buf[100], ip1[20], ip2[20]; sprintf (buf, "echo-daemon %s, %s/%u, discard-daemon %s, %s/%u\r\n\r\n", do_echo ? "yes" : "no", _inet_ntoa(ip1,echo_host), echo_port, do_disc ? "yes" : "no", _inet_ntoa(ip2,disc_host), disc_port); dbug_write_raw (buf); #endif if (do_echo) { udp_listen (&udp_echo_sock, echo_host, echo_port, 0, (ProtoHandler)udp_handler); udp_echo_sock.sockmode |= UDP_MODE_NOCHK; tcp_listen (&tcp_echo_sock, echo_host, echo_port, 0, NULL, 0); } if (do_disc) { udp_listen (&udp_disc_sock, disc_host, disc_port, 0, (ProtoHandler)udp_handler); udp_disc_sock.sockmode |= UDP_MODE_NOCHK; tcp_listen (&tcp_disc_sock, disc_host, disc_port, 0, NULL, 0); } if (do_echo || do_disc) addwattcpd (echo_discard_daemon); }
void pppLinkStatusCallback(void *ctx, int errCode, void *arg) { switch(errCode) { case PPPERR_NONE: /* No error. */ { struct ppp_addrs *ppp_addrs = arg; printf("pppLinkStatusCallback: PPPERR_NONE"); printf(" our_ipaddr=%s", _inet_ntoa(ppp_addrs->our_ipaddr.addr)); printf(" his_ipaddr=%s", _inet_ntoa(ppp_addrs->his_ipaddr.addr)); printf(" netmask=%s", _inet_ntoa(ppp_addrs->netmask.addr)); printf(" dns1=%s", _inet_ntoa(ppp_addrs->dns1.addr)); printf(" dns2=%s\n", _inet_ntoa(ppp_addrs->dns2.addr)); } break; case PPPERR_PARAM: /* Invalid parameter. */ printf("pppLinkStatusCallback: PPPERR_PARAM\n"); break; case PPPERR_OPEN: /* Unable to open PPP session. */ printf("pppLinkStatusCallback: PPPERR_OPEN\n"); break; case PPPERR_DEVICE: /* Invalid I/O device for PPP. */ printf("pppLinkStatusCallback: PPPERR_DEVICE\n"); break; case PPPERR_ALLOC: /* Unable to allocate resources. */ printf("pppLinkStatusCallback: PPPERR_ALLOC\n"); break; case PPPERR_USER: /* User interrupt. */ printf("pppLinkStatusCallback: PPPERR_USER\n"); break; case PPPERR_CONNECT: /* Connection lost. */ printf("pppLinkStatusCallback: PPPERR_CONNECT\n"); break; case PPPERR_AUTHFAIL: /* Failed authentication challenge. */ printf("pppLinkStatusCallback: PPPERR_AUTHFAIL\n"); break; case PPPERR_PROTOCOL: /* Failed to meet protocol. */ printf("pppLinkStatusCallback: PPPERR_PROTOCOL\n"); break; default: printf("pppLinkStatusCallback: unknown errCode %d\n", errCode); break; } }
static void tcp_accept_callback( const int lst ) { D(bug("[%d] tcp_accept_callback()\r\n", lst)); struct sockaddr_in to; memset( &to, 0, sizeof(to) ); to.sin_family = AF_INET; int tolen = sizeof(to); SOCKET s = _accept( l_sockets[lst].s, (struct sockaddr *)&to, &tolen ); if( s == INVALID_SOCKET ) { D(bug("[%d] connection not accepted, error code %d\r\n", lst, _WSAGetLastError())); } else { _WSAEventSelect( s, 0, 0 ); uint16 src_port = l_sockets[lst].port; uint16 dest_port = ntohs(to.sin_port); uint32 ip_dest = ntohl(to.sin_addr.s_addr); D(bug("[%d] connection accepted, local port:%d, remote %s:%d\r\n", lst, src_port, _inet_ntoa(to.sin_addr), dest_port)); if( l_sockets[lst].ip != 0 && l_sockets[lst].ip != ip_dest ) { _closesocket( s ); D(bug("[%d] authorization failure. connection closed.\r\n", lst )); } else { int t = alloc_new_socket( src_port, dest_port, ip_dest ); if( t < 0 ) { D(bug("<%d> out of slot space, connection dropped\r\n", t )); free_socket(t); } else { sockets[t].s = s; sockets[t].state = LISTEN; sockets[t].src_port = src_port; sockets[t].dest_port = dest_port; sockets[t].ip_src = macos_ip_address; sockets[t].ip_dest = ip_dest; sockets[t].seq_out = 0x00000001; sockets[t].seq_in = 0; // not known yet sockets[t].mac_ack = sockets[t].seq_out; // zero out pending bytes tcp_reply( SYN, t ); sockets[t].seq_out++; sockets[t].state = SYN_SENT; sockets[t].time_wait = GetTickCount() + SYN_FLOOD_PROTECTION_TIMEOUT; D(bug("<%d> Connect: LISTEN -> SYN_SENT\r\n", t)); _WSAResetEvent( sockets[t].ev ); if( SOCKET_ERROR == _WSAEventSelect( sockets[t].s, sockets[t].ev, FD_CLOSE ) ) { D(bug("<%d> WSAEventSelect() failed with error code %d\r\n", t, _WSAGetLastError())); } // No data from the remote host is needed until the connection is established. // So don't initiate read yet. } } } }
/** * Handle ICMP_REDIRECT messages. */ static void icmp_redirect (const union ICMP_PKT *icmp, const in_Header *ip, const in_Header *orig_ip, int code) { DWORD new_ip = intel (icmp->ip.ipaddr); DWORD old_ip = intel (orig_ip->destination); const char *msg; if (new_ip == old_ip) { /* Possibly because we and router use different netmasks */ } else if ((new_ip ^ my_ip_addr) & sin_mask) /* new host not on subnet */ { char buf[100]; strcpy (buf, ", GW = "); strcat (buf, _inet_ntoa(NULL,new_ip)); icmp_bogus (ip, ICMP_REDIRECT, buf); return; } msg = icmp_redirect_str[code]; icmp_print (1, msg, ip->source); switch (orig_ip->proto) { #if !defined(USE_UDP_ONLY) case TCP_PROTO: if (do_redirect.tcp) /* do it to some socket */ _tcp_cancel (orig_ip, ICMP_REDIRECT, code, msg, &new_ip); break; #endif case UDP_PROTO: if (do_redirect.udp) _udp_cancel (orig_ip, ICMP_REDIRECT, code, msg, &new_ip); break; case ICMP_PROTO: if (do_redirect.icmp) { /* _ip_recursion = TRUE; !! */ _arp_register (new_ip, old_ip); /* _ip_recursion = FALSE; !! */ } break; case IGMP_PROTO: if (do_redirect.igmp) { /* _ip_recursion = TRUE; !! */ _arp_register (new_ip, old_ip); /* _ip_recursion = FALSE; !! */ } break; } }
void psocket (const sock_type *s) { char buf[20]; (*_outch) ('['); outs (_inet_ntoa(buf, s->tcp.hisaddr)); (*_outch) (':'); itoa (s->tcp.hisport, buf, 10); outs (buf); (*_outch) (']'); }
static void icmp_print (int dbg_lvl, const char *msg, DWORD src) { if (debug_on < dbg_lvl) return; outs ("\nICMP: "); if (src) { outs ("("); outs (_inet_ntoa(NULL,intel(src))); outs ("): "); } outsnl (_LANG(msg)); }
static inline void sniff_loop_ip(session_t *s, int len, const u_char *packet) { const struct iphdr *ip; int size_ip; CHECK_LEN(sizeof(struct iphdr)) ip = (struct iphdr *) (packet); size_ip = ip->ip_hl*4; if (size_ip < 20) { debug_error("sniff_loop_ip() * Invalid IP header length: %u bytes\n", size_ip); return; } if (ip->ip_p == IPPROTO_TCP) sniff_loop_tcp(s, len - size_ip, packet + size_ip, ip, size_ip); else if (ip->ip_p == IPPROTO_UDP) sniff_loop_udp(s, len - size_ip, packet + size_ip, ip); else if (ip->ip_p == IPPROTO_ICMP) { /* ICMP, stub only */ const struct icmphdr *icmp; CHECK_LEN(size_ip + sizeof(struct icmphdr)); icmp = (struct icmphdr *) (packet + size_ip); debug_function("sniff_loop_ip() IP/ICMP %15s <==> %15s TYPE: %d CODE: %d CHKSUM: %d\n", _inet_ntoa(ip->ip_src), /* src ip */ _inet_ntoa(ip->ip_dst), /* dest ip */ icmp->icmp_type, icmp->icmp_code, icmp->icmp_cksum); /* XXX */ } else { /* other, implement if u want to || die. */ debug_error("sniff_loop_ip() IP/0x%x %15s <==> %15s\n", ip->ip_p, /* protocol */ _inet_ntoa(ip->ip_src), /* src ip */ _inet_ntoa(ip->ip_dst)); /* dest ip */ } }
static inline void sniff_loop_udp(session_t *s, int len, const u_char *packet, const struct iphdr *ip) { #define RIVCHAT_PACKET_LEN 328 static const char rivchat_magic[11] = { 'R', 'i', 'v', 'C', 'h', 'a', 't' /* here NULs */}; /* RivChat\0\0\0\0 */ /* XXX here, make some struct with known UDP services, and demangler-function */ const struct udphdr *udp; connection_t *hdr; const char *payload; int size_payload; /* XXX, it's enough? */ /* code copied from: http://gpsbots.com/tutorials/sniff_packets.php */ CHECK_LEN(sizeof(struct udphdr)); udp = (struct udphdr *) (packet); hdr = sniff_udp_get(ip, udp); payload = (char *) (packet + sizeof(struct udphdr)); size_payload = g_ntohs(udp->th_len)-sizeof(struct udphdr); CHECK_LEN(sizeof(struct udphdr) + size_payload); debug_error("sniff_loop_udp() IP/UDP %15s:%5d <==> %15s:%5d\n", _inet_ntoa(hdr->srcip), /* src ip */ hdr->srcport, /* src port */ _inet_ntoa(hdr->dstip), /* dest ip */ hdr->dstport); /* dest port */ if (size_payload == RIVCHAT_PACKET_LEN && !memcmp(payload, rivchat_magic, sizeof(rivchat_magic))) { /* RIVCHAT [check based on header (11b), ~100% hit] */ sniff_rivchat(s, hdr, (rivchat_packet *) payload, size_payload); } else if (hdr->srcport == 53 || hdr->dstport == 53) { /* DNS [check based on port, ~80% hit] */ sniff_dns(s, hdr, (DNS_HEADER *) payload, size_payload); } else { /* OTHER PROTOs, feel free */ debug_error("NOT RIVCHAT/ NOT DNS:\n"); tcp_print_payload((u_char *) payload, size_payload); } }
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size) { if (af != AF_INET) { errno = EAFNOSUPPORT; return NULL; } if (size < 18) { errno = ENOSPC; return NULL; } /* This isn't strictly correct because it means we are not re-entrant. Really we need to rework _itoa() to have a re-entrant base form, then rework inet_ntoa to use inet_ntop FIXME */ return strcpy(dst, _inet_ntoa(*(uint32_t *)src)); }
/* * This functiom is called once each second. */ static void check_dead_gw (void) { char buf[20]; static int i = 0; if (i >= gate_top) i = 0; for ( ; i < gate_top; i++) { struct gate_entry *gw = &gate_list [i]; eth_address eth; if (!is_on_LAN(gw->gate_ip)) continue; if (!LAN_lookup(gw->gate_ip,ð)) continue; if (gw->chk_timer == 0UL || !chk_timeout(gw->chk_timer)) { gw->chk_timer = set_timeout (DEAD_GW_TIMEOUT); continue; } if (gw->echo_pending && _chk_ping(gw->gate_ip,NULL) == (DWORD)-1) { gw->is_dead = TRUE; gw->echo_pending = FALSE; TCP_CONSOLE_MSG (1, ("Dead default GW %s (%d) detected\n", _inet_ntoa(NULL,gw->gate_ip), i)); } if (ping_gateway (gw->gate_ip, eth)) gw->echo_pending = TRUE; gw->chk_timer = set_timeout (DEAD_GW_TIMEOUT); return; /* only one ping per interval */ } }
void write_tcp( tcp_t *tcp, int len ) { if(len < sizeof(tcp_t)) { D(bug("<%d> Too small tcp packet(%d) on unknown slot, dropped\r\n", -1, len)); return; } uint16 src_port = ntohs(tcp->src_port); uint16 dest_port = ntohs(tcp->dest_port); BOOL ok = true; BOOL handle_data = false; BOOL initiate_read = false; EnterCriticalSection( &tcp_section ); int t = find_socket( src_port, dest_port ); if(t < 0) { t = alloc_new_socket( src_port, dest_port, ntohl(tcp->ip.dest) ); ok = t >= 0; } if(ok) { D(bug("<%d> write_tcp %d bytes from port %d to port %d\r\n", t, len, src_port, dest_port)); } else { D(bug("<%d> FAILED write_tcp %d bytes from port %d to port %d\r\n", t, len, src_port, dest_port)); } if( ok && ISSET(tcp->flags,RST) ) { D(bug("<%d> RST set, resetting socket\r\n", t)); if( sockets[t].s != INVALID_SOCKET ) { D(bug("<%d> doing an extra shutdown (ie4)\r\n", t)); _shutdown( sockets[t].s, SD_BOTH ); } free_socket( t ); ok = false; } if(ok) { D(bug("<%d> State machine start = %s\r\n", t, STATENAME(sockets[t].state))); // always update receive window sockets[t].mac_window = ntohs(tcp->window); int header_len = tcp->header_len >> 2; int option_bytes = header_len - 20; char *data = (char *)tcp + sizeof(tcp_t) + option_bytes; int dlen = len - sizeof(tcp_t) - option_bytes; if( !ISSET(tcp->flags,ACK) ) { D(bug("<%d> ACK not set\r\n", t)); } if( ISSET(tcp->flags,SYN) ) { D(bug("<%d> SYN set\r\n", t)); // Note that some options are valid even if there is no SYN. // I don't care about those however. uint32 new_mss; process_options( t, (uint8 *)data - option_bytes, option_bytes, new_mss ); if(new_mss) { sockets[t].mac_mss = (int)new_mss; if( new_mss < sockets[t].buffers_read[0].len ) { sockets[t].buffers_read[0].len = new_mss; } D(bug("<%d> Max segment size set to %d\r\n", t, new_mss)); } } if( ISSET(tcp->flags,FIN) ) { D(bug("<%d> FIN set\r\n", t)); } // The sequence number Mac expects to see next time. sockets[t].mac_ack = ntohl(tcp->ack); D(bug("<%d> From Mac: Seq=%d, Ack=%d, window=%d, router Seq=%d\r\n", t, ntohl(tcp->seq), sockets[t].mac_ack, sockets[t].mac_window, sockets[t].seq_out)); if( sockets[t].stream_to_mac_stalled_until && sockets[t].mac_ack == sockets[t].seq_out && (sockets[t].state == ESTABLISHED || sockets[t].state == CLOSE_WAIT) ) { if( has_mac_read_space(t) ) { initiate_read = true; sockets[t].stream_to_mac_stalled_until = 0; D(bug("<%d> read resumed, mac can accept more data\r\n", t)); } } switch( sockets[t].state ) { case CLOSED: sockets[t].src_port = src_port; sockets[t].dest_port = dest_port; sockets[t].ip_src = ntohl(tcp->ip.src); sockets[t].ip_dest = ntohl(tcp->ip.dest); if( ISSET(tcp->flags,SYN) ) { sockets[t].seq_out = 0x00000001; sockets[t].seq_in = ntohl(tcp->seq) + 1; _WSAResetEvent( sockets[t].ev ); if( SOCKET_ERROR == _WSAEventSelect( sockets[t].s, sockets[t].ev, FD_CONNECT | FD_CLOSE ) ) { D(bug("<%d> WSAEventSelect() failed with error code %d\r\n", t, _WSAGetLastError())); } D(bug("<%d> connecting local port %d to remote %s:%d\r\n", t, src_port, _inet_ntoa(sockets[t].from.sin_addr), dest_port)); sockets[t].state = LISTEN; if( _WSAConnect( sockets[t].s, (const struct sockaddr *)&sockets[t].from, sockets[t].from_len, NULL, NULL, NULL, NULL ) == SOCKET_ERROR ) { int connect_error = _WSAGetLastError(); if( connect_error == WSAEWOULDBLOCK ) { D(bug("<%d> WSAConnect() i/o pending.\r\n", t)); } else { D(bug("<%d> WSAConnect() failed with error %d.\r\n", t, connect_error)); } } else { D(bug("<%d> WSAConnect() ok.\r\n", t)); } } else { if( ISSET(tcp->flags,FIN) ) { D(bug("<%d> No SYN but FIN on a closed socket.\r\n", t)); free_socket(t); } else { D(bug("<%d> No SYN on a closed socket. resetting.\r\n", t)); free_socket(t); } } break; case LISTEN: // handled in connect callback break; case SYN_SENT: if( ISSET(tcp->flags,SYN) && ISSET(tcp->flags,ACK) ) { sockets[t].seq_in = ntohl(tcp->seq) + 1; tcp_reply( ACK, t ); sockets[t].state = ESTABLISHED; initiate_read = true; sockets[t].accept_more_data_from_mac = true; sockets[t].time_wait = 0; } else if( ISSET(tcp->flags,SYN) ) { sockets[t].seq_in = ntohl(tcp->seq) + 1; tcp_reply( ACK|SYN, t ); sockets[t].seq_out++; sockets[t].state = SYN_RCVD; sockets[t].time_wait = 0; } else if( ISSET(tcp->flags,ACK) ) { // What was the bright idea here. D(bug("<%d> State is SYN_SENT, but got only ACK from Mac??\r\n", t)); sockets[t].state = FINWAIT_2; sockets[t].time_wait = 0; } break; case SYN_RCVD: if( ISSET(tcp->flags,ACK) ) { sockets[t].state = ESTABLISHED; handle_data = true; initiate_read = true; sockets[t].accept_more_data_from_mac = true; } break; case ESTABLISHED: if( ISSET(tcp->flags,FIN) ) { sockets[t].seq_in++; tcp_reply( ACK, t ); _shutdown( sockets[t].s, SD_SEND ); sockets[t].state = CLOSE_WAIT; } handle_data = true; break; case CLOSE_WAIT: // handled in tcp_read_completion break; case LAST_ACK: if( ISSET(tcp->flags,ACK) ) { D(bug("<%d> LAST_ACK received, socket closed\r\n", t)); free_socket( t ); } break; case FINWAIT_1: if( ISSET(tcp->flags,FIN) && ISSET(tcp->flags,ACK) ) { sockets[t].seq_in++; tcp_reply( ACK, t ); if(sockets[t].remote_closed) { _closesocket(sockets[t].s); sockets[t].s = INVALID_SOCKET; } else { _shutdown( sockets[t].s, SD_SEND ); } sockets[t].state = TIME_WAIT; sockets[t].time_wait = GetTickCount() + 2 * sockets[t].msl; } else if( ISSET(tcp->flags,FIN) ) { sockets[t].seq_in++; tcp_reply( ACK, t ); if(sockets[t].remote_closed) { _closesocket(sockets[t].s); sockets[t].s = INVALID_SOCKET; } else { _shutdown( sockets[t].s, SD_SEND ); } sockets[t].state = CLOSING; } else if( ISSET(tcp->flags,ACK) ) { sockets[t].state = FINWAIT_2; } break; case FINWAIT_2: if( ISSET(tcp->flags,FIN) ) { sockets[t].seq_in++; tcp_reply( ACK, t ); if(sockets[t].remote_closed) { _closesocket(sockets[t].s); sockets[t].s = INVALID_SOCKET; } else { _shutdown( sockets[t].s, SD_SEND ); } sockets[t].state = TIME_WAIT; sockets[t].time_wait = GetTickCount() + 2 * sockets[t].msl; } break; case CLOSING: if( ISSET(tcp->flags,ACK) ) { sockets[t].state = TIME_WAIT; sockets[t].time_wait = GetTickCount() + 2 * sockets[t].msl; } break; case TIME_WAIT: // Catching stray packets: wait MSL * 2 seconds, -> CLOSED // Timer already set since we might not get here at all. // I'm using exceptionally low MSL value (5 secs). D(bug("<%d> time wait, datagram discarded\r\n", t)); break; } // The "t" descriptor may already be freed. However, it's safe // to peek the state value inside the critical section. D(bug("<%d> State machine end = %s\r\n", t, STATENAME(sockets[t].state))); D(bug("<%d> handle_data=%d, initiate_read=%d\r\n", t, handle_data, initiate_read)); if( handle_data && dlen && sockets[t].accept_more_data_from_mac ) { if( sockets[t].seq_in != ntohl(tcp->seq) ) { D(bug("<%d> dropping duplicate datagram seq=%d, expected=%d\r\n", t, ntohl(tcp->seq), sockets[t].seq_in)); } else { set_ttl( t, tcp->ip.ttl ); struct sockaddr_in to; memset( &to, 0, sizeof(to) ); to.sin_family = AF_INET; to.sin_port = tcp->dest_port; to.sin_addr.s_addr = tcp->ip.dest; D(bug("<%d> sending %d bytes to remote host\r\n", t, dlen)); sockets[t].accept_more_data_from_mac = false; if( dlen > MAX_SEGMENT_SIZE ) { D(bug("<%d> IMPOSSIBLE: b_send() dropped %d bytes! \r\n", t, dlen-MAX_SEGMENT_SIZE)); dlen = MAX_SEGMENT_SIZE; } memcpy( sockets[t].buffers_write[0].buf, data, dlen ); sockets[t].buffers_write[0].len = dlen; sockets[t].bytes_remaining_to_send = dlen; sockets[t].bytes_to_send = dlen; bool send_now = false; if( ISSET(tcp->flags,PSH) ) { send_now = true; } else { // todo -- delayed send send_now = true; } if(send_now) { // Patch ftp server or client address if needed. int lst = 1; bool is_pasv; uint16 ftp_data_port = 0; if(ftp_is_ftp_port(sockets[t].src_port)) { // Local ftp server may be entering to passive mode. is_pasv = true; ftp_parse_port_command( sockets[t].buffers_write[0].buf, dlen, ftp_data_port, is_pasv ); } else if(ftp_is_ftp_port(sockets[t].dest_port)) { // Local ftp client may be using port command. is_pasv = false; ftp_parse_port_command( sockets[t].buffers_write[0].buf, dlen, ftp_data_port, is_pasv ); } if(ftp_data_port) { D(bug("<%d> ftp %s command detected, port %d\r\n", t, (is_pasv ? "SERVER PASV REPLY" : "CLIENT PORT"), ftp_data_port )); // Note: for security reasons, only allow incoming connection from sockets[t].ip_dest lst = alloc_listen_socket( ftp_data_port, sockets[t].ip_dest, 0/*iface*/, true ); if(lst < 0) { D(bug("<%d> no more free slots\r\n", t)); } else { // First start listening (need to know the local name later) tcp_start_listen( lst ); // When t is closed, lst must be closed too. sockets[t].child = lst; l_sockets[lst].parent = t; // Find out the local name struct sockaddr_in name; int namelen = sizeof(name); memset( &name, 0, sizeof(name) ); if( _getsockname( sockets[t].s, (struct sockaddr *)&name, &namelen ) == SOCKET_ERROR ) { D(bug("_getsockname() failed, error=%d\r\n", _WSAGetLastError() )); } ftp_modify_port_command( sockets[t].buffers_write[0].buf, dlen, MAX_SEGMENT_SIZE, ntohl(name.sin_addr.s_addr), ftp_data_port, is_pasv ); sockets[t].buffers_write[0].len = dlen; sockets[t].bytes_remaining_to_send = dlen; // Do not change "bytes_to_send" field as it is used for ack calculation } } // end of ftp patch if(!b_send(t)) { // on error, close the ftp data listening socket if one was created if(lst >= 0) { D(bug("[%d] closing listening port %d after write error\r\n", t, l_sockets[lst].port)); _closesocket( l_sockets[lst].s ); l_sockets[lst].s = INVALID_SOCKET; l_sockets[lst].port = 0; l_sockets[lst].ip = 0; l_sockets[lst].parent = -1; sockets[t].child = -1; } } } } } if(initiate_read) { if(!b_recfrom(t)) { // post icmp error message } } } LeaveCriticalSection( &tcp_section ); }
static inline void sniff_loop_tcp(session_t *s, int len, const u_char *packet, const struct iphdr *ip, int size_ip) { /* XXX here, make some struct with known TCP services, and demangler-function */ const struct tcphdr *tcp; int size_tcp; connection_t *hdr; const char *payload; int size_payload; CHECK_LEN(sizeof(struct tcphdr)) tcp = (struct tcphdr*) (packet); size_tcp = TH_OFF(tcp)*4; if (size_tcp < 20) { debug_error("sniff_loop_tcp() * Invalid TCP header length: %u bytes\n", size_tcp); return; } size_payload = g_ntohs(ip->ip_len) - (size_ip + size_tcp); CHECK_LEN(size_tcp + size_payload); payload = (char *) (packet + size_tcp); hdr = sniff_tcp_find_connection(ip, tcp); debug_function("sniff_loop_tcp() IP/TCP %15s:%5d <==> %15s:%5d %s (SEQ: %lx ACK: %lx len: %d)\n", _inet_ntoa(hdr->srcip), /* src ip */ hdr->srcport, /* src port */ _inet_ntoa(hdr->dstip), /* dest ip */ hdr->dstport, /* dest port */ tcp_print_flags(tcp->th_flags), /* tcp flags */ g_htonl(tcp->th_seq), /* seq */ g_htonl(tcp->th_ack), /* ack */ size_payload); /* payload len */ /* XXX check tcp flags */ if (!size_payload) return; /* XXX what proto ? check based on ip + port? */ if (hdr->dstport == 80 || hdr->srcport == 80) { /* HTTP [basic check on magic values, ~80% hit] */ static const char http_magic11[] = { 'H', 'T', 'T', 'P', '/', '1', '.', '1', ' ' }; /* HTTP/1.1 */ static const char http_magic10[] = { 'H', 'T', 'T', 'P', '/', '1', '.', '0', ' ' }; /* HTTP/1.0 */ static const char http_get_magic[] = { 'G', 'E', 'T', ' ' }; /* GET */ static const char http_post_magic[] = { 'P', 'O', 'S', 'T', ' ' }; /* POST */ /* SERVER REPLIES: */ if ( (size_payload > sizeof(http_magic10) && !memcmp(payload, http_magic10, sizeof(http_magic10))) || (size_payload > sizeof(http_magic11) && !memcmp(payload, http_magic11, sizeof(http_magic11))) ) { // debug_error("HTTP DATA FOLLOW\n"); // tcp_print_payload((u_char *) payload, size_payload); return; /* done */ } /* CLIENT REQUESTs: */ if ( (size_payload > sizeof(http_get_magic) && !memcmp(payload, http_get_magic, sizeof(http_get_magic))) || (size_payload > sizeof(http_post_magic) && !memcmp(payload, http_post_magic, sizeof(http_post_magic))) ) { // debug_error("HTTP DATA FOLLOW?\n"); // tcp_print_payload((u_char *) payload, size_payload); return; /* done */ } } sniff_gg(s, hdr, (gg_header *) payload, size_payload); /* GG [no check, ~3% hit] */ }
/* * Handler for incoming ICMP packets */ void icmp_handler (const in_Header *ip, BOOL broadcast) { union icmp_pkt *icmp; in_Header *orig_ip; int len, type, code; BOOL for_me, i_orig; /* is it for me, did I originate it */ const char *msg; DEBUG_RX (NULL, ip); if (block_icmp) /* application is handling ICMP; not needed */ return; len = in_GetHdrLen (ip); icmp = (union icmp_pkt*) ((BYTE*)ip + len); len = intel16 (ip->length) - len; for_me = (DWORD) (intel(ip->destination) - my_ip_addr) <= multihomes; if (!for_me || broadcast) /* drop broadcast pings.. */ return; if (len < sizeof(icmp->info)) { STAT (icmpstats.icps_tooshort++); return; } if (checksum(icmp,len) != 0xFFFF) { STAT (icmpstats.icps_checksum++); icmp_print (1, _LANG("bad checksum"), ip->source); return; } type = icmp->unused.type; code = icmp->unused.code; orig_ip = &icmp->ip.ip; i_orig = is_local_addr (intel(orig_ip->source)); if (type == ICMP_MASKREPLY) { if (!_domask_req) return; i_orig = TRUE; } /* !! this needs work */ if (!i_orig && (type != ICMP_ECHOREPLY && type != ICMP_ECHO && type != ICMP_IREQREPLY && type != ICMP_TSTAMP)) { icmp_bogus (ip, type, NULL); return; } switch (type) { case ICMP_ECHOREPLY: /* check if we were waiting for it */ STAT (icmpstats.icps_inhist[ICMP_ECHOREPLY]++); ping_hcache = intel (ip->source); ping_tcache = set_timeout (1000) - *(DWORD*)&icmp->echo.identifier; if (ping_tcache > 0x7FFFFFFFL) ping_tcache += 0x1800B0L; ping_number = *(DWORD*)(((BYTE*)&icmp->echo.identifier) + 4); return; case ICMP_UNREACH: STAT (icmpstats.icps_inhist[ICMP_UNREACH]++); if (code < DIM(icmp_unreach_str)) { icmp_print (1, msg = icmp_unreach_str[code], ip->source); #if !defined(USE_UDP_ONLY) if (orig_ip->proto == TCP_PROTO) _tcp_cancel (orig_ip, type, msg, 0); else #endif if (orig_ip->proto == UDP_PROTO) _udp_cancel (orig_ip, type, msg, 0); } else STAT (icmpstats.icps_badcode++); return; case ICMP_SOURCEQUENCH: STAT (icmpstats.icps_inhist[ICMP_SOURCEQUENCH]++); #if !defined(USE_UDP_ONLY) if (orig_ip->proto == TCP_PROTO) { icmp_print (1, _LANG("Source Quench"), ip->source); _tcp_cancel (orig_ip, type, NULL, 0); } #endif return; case ICMP_REDIRECT: STAT (icmpstats.icps_inhist[ICMP_REDIRECT]++); if (code < 4) { DWORD new_gw = intel (icmp->ip.ipaddr); /* Check if new gateway is on our subnet */ if ((new_gw ^ my_ip_addr) & sin_mask) { char buf[100], adr[20]; strcpy (buf, ", GW = "); strcat (buf, _inet_ntoa(adr,new_gw)); icmp_bogus (ip, type, buf); return; } icmp_print (1, msg = icmp_redirect_str[code], ip->source); switch (orig_ip->proto) { #if !defined(USE_UDP_ONLY) case TCP_PROTO: if (do_redirect.tcp) /* do it to some socket */ _tcp_cancel (orig_ip, type, msg, new_gw); break; #endif case UDP_PROTO: if (do_redirect.udp) _udp_cancel (orig_ip, type, msg, new_gw); break; case ICMP_PROTO: if (do_redirect.icmp) { _ip_recursion = 1; _arp_register (new_gw, intel(orig_ip->destination), 0); _ip_recursion = 0; } break; case IGMP_PROTO: if (do_redirect.igmp) { _ip_recursion = 1; _arp_register (new_gw, intel(orig_ip->destination), 0); _ip_recursion = 0; } break; } } else STAT (icmpstats.icps_badcode++); return; case ICMP_ECHO: STAT (icmpstats.icps_inhist[ICMP_ECHO]++); icmp_print (2, _LANG("PING requested of us"), ip->source); { /* Extract eth-address and create Echo reply packet. */ struct _pkt *pkt; union icmp_pkt *newicmp; if (!icmp_chk_src(ip,ICMP_ECHO)) return; pkt = (struct _pkt*) _eth_formatpacket (MAC_SRC(ip), IP_TYPE); newicmp = &pkt->icmp; /* Don't let a huge reassembled ICMP-packet kill us. */ len = min (len, mtu - sizeof(*ip)); memcpy (newicmp, icmp, len); newicmp->echo.type = ICMP_ECHOREPLY; newicmp->echo.code = code; /* Use supplied ip values in case we ever multi-home. * Note that ip values are still in network order. */ icmp_send (pkt, ip->destination, ip->source, len); icmp_print (2, _LANG("PING reply sent"), 0); } return; case ICMP_TIMXCEED: if (code >= DIM(icmp_exceed_str)) { STAT (icmpstats.icps_badcode++); return; } STAT (icmpstats.icps_inhist[ICMP_TIMXCEED]++); if (code != 1) switch (orig_ip->proto) { #if !defined(USE_UDP_ONLY) case TCP_PROTO: icmp_print (1, icmp_exceed_str[code], ip->source); _tcp_cancel (orig_ip, ICMP_TIMXCEED, NULL, 0); break; #endif case UDP_PROTO: icmp_print (1, icmp_exceed_str[code], ip->source); _udp_cancel (orig_ip, ICMP_TIMXCEED, NULL, 0); break; } return; case ICMP_PARAMPROB: STAT (icmpstats.icps_inhist[ICMP_PARAMPROB]++); switch (orig_ip->proto) { #if !defined(USE_UDP_ONLY) case TCP_PROTO: icmp_print (0, _LANG(icmp_type_str[type]), ip->source); _tcp_cancel (orig_ip, type, NULL, 0); break; #endif case UDP_PROTO: icmp_print (0, _LANG(icmp_type_str[type]), ip->source); _udp_cancel (orig_ip, type, NULL, 0); break; } return; case ICMP_ROUTERADVERT: /* todo !! */ STAT (icmpstats.icps_inhist[ICMP_ROUTERADVERT]++); icmp_print (1, _LANG(icmp_type_str[type]), ip->source); return; case ICMP_ROUTERSOLICIT: /* todo !! */ STAT (icmpstats.icps_inhist[ICMP_ROUTERSOLICIT]++); icmp_print (1, _LANG(icmp_type_str[type]), ip->source); return; case ICMP_TSTAMP: STAT (icmpstats.icps_inhist[ICMP_TSTAMP]++); icmp_print (1, _LANG(icmp_type_str[type]), ip->source); /* todo!!, send reply? */ return; case ICMP_TSTAMPREPLY: STAT (icmpstats.icps_inhist[ICMP_TSTAMPREPLY]++); icmp_print (1, _LANG(icmp_type_str[type]), ip->source); /* todo!!, should store */ return; case ICMP_IREQ: STAT (icmpstats.icps_inhist[ICMP_IREQ]++); icmp_print (1, _LANG(icmp_type_str[type]), ip->source); /* todo!!, send reply */ return; case ICMP_IREQREPLY: STAT (icmpstats.icps_inhist[ICMP_IREQREPLY]++); icmp_print (1, _LANG(icmp_type_str[type]), ip->source); /* todo!!, send reply upwards */ return; case ICMP_MASKREQ: STAT (icmpstats.icps_inhist[ICMP_MASKREQ]++); break; case ICMP_MASKREPLY: STAT (icmpstats.icps_inhist[ICMP_MASKREPLY]++); icmp_print (0, _LANG(icmp_type_str[type]), ip->source); if ((icmp->mask.identifier == addr_mask_id) && (icmp->mask.sequence == addr_mask_seq-1) && sin_mask != intel(icmp->mask.mask)) outsnl ("Conflicting net-mask from \"ICMP Addr Mask Reply\"\7"); addr_mask_id = 0; return; } }