int sock_loopback (in_Header *ip) { if (ip->proto == TCP_PROTO) { tcp_Header *tcp = (tcp_Header*) ((BYTE*)ip + in_GetHdrLen(ip)); if (intel16(tcp->dstPort) == test_port) { BYTE flags = tcp->flags & tcp_FlagMASK; if (flags == tcp_FlagSYN) { tcp->flags = tcp_FlagACK | tcp_FlagSYN; return fix_tcp_packet (ip, tcp, 1, 0); } if (flags & tcp_FlagACK) { char *data = (char*)tcp + (tcp->offset << 2); if (!strncmp(data,"HELO",4)) { strcpy (data, "Welcome to loop-back handler"); return fix_tcp_packet (ip, tcp, 4, strlen(data) + 1); } if (!strncmp(data,"QUIT",4)) { strcpy (data, "Bye from loop-back handler"); return fix_tcp_packet (ip, tcp, 4, strlen(data) + 1); } } } } return (-1); }
/** * Send an ICMP destination/protocol unreachable back to 'ip->source'. * Limit the rate of these to 20 per second. Ref. RFC-1812. */ int icmp_send_unreach (const in_Header *ip, int code) { static DWORD next_time = 0UL; struct _pkt *pkt; union ICMP_PKT *unr; unsigned len; if (!icmp_check(ip,ICMP_UNREACH)) return (0); if (next_time && !chk_timeout(next_time)) return (0); next_time = set_timeout (50); pkt = (struct _pkt*) _eth_formatpacket (MAC_SRC(ip), IP4_TYPE); unr = &pkt->icmp; len = intel16 (ip->length) - in_GetHdrLen (ip); len = min (len, sizeof(*ip)+sizeof(unr->unused.spares)); icmp_print (1, _LANG(icmp_unreach_str[code]), ip->destination); memcpy (&unr->unused.ip, ip, len); unr->unused.type = ICMP_UNREACH; unr->unused.code = (BYTE) code; return icmp_send (pkt, ip->destination, ip->source, sizeof(unr->unused)); }
/* * igmp_handler - handles the incoming IGMP packets * * void igmp_handler (in_Header *ip) * Where: * ip is the IP packet in question * * Returns: None * */ void igmp_handler (const in_Header *ip, BOOL broadcast) { BYTE i; DWORD host; BOOL found = 0; WORD len = in_GetHdrLen (ip); IGMP_packet *igmp = (IGMP_packet*) ((BYTE*)ip + len); DEBUG_RX (NULL, ip); if (len < sizeof(*igmp)) { STAT (igmpstats.igps_rcv_tooshort++); return; } if (checksum(igmp,sizeof(*igmp)) != 0xFFFF) { STAT (igmpstats.igps_rcv_badsum++); return; } host = intel (igmp->address); /* Determine whether this is a report or a query */ switch (igmp->type) { case IGMP_QUERY: STAT (igmpstats.igps_rcv_queries++); for (i = 0; i < IPMULTI_SIZE; i++) if (_ipmulti[i].active && _ipmulti[i].ina != ALL_SYSTEMS && _ipmulti[i].replytime == 0) { _ipmulti[i].replytime = set_timeout (Random(500,1000)); found = 1; } if (!found && !broadcast) STAT (igmpstats.igps_rcv_badqueries++); break; case IGMP_REPORT: STAT (igmpstats.igps_rcv_reports++); for (i = 0; i < IPMULTI_SIZE; i++) if (_ipmulti[i].active && _ipmulti[i].ina == host && host != ALL_SYSTEMS) { _ipmulti[i].replytime = 0; found = 1; STAT (igmpstats.igps_rcv_ourreports++); break; } if (!found && !broadcast) STAT (igmpstats.igps_rcv_badreports++); break; } }
/* * We have been called with an ip-packet located on stack in * _eth_send_loopback(). Hence, it's safe to call _eth_send() again * here. MAC-header is in front of 'ip'. */ int loopback_device (in_Header *ip) { int ip_hlen, ip_len; DWORD ip_dst; DWORD ip_ofs; WORD ip_flg; if (!loopback_enable || !_chk_ip_header(ip)) /* silently discard */ return (-1); ip_hlen = in_GetHdrLen (ip); /* length of IP-header (w/options) */ ip_len = intel16 (ip->length); /* total length of IP-packet */ ip_dst = ip->destination; ip->destination = ip->source; /* swap source and destination */ ip->source = ip_dst; ip->checksum = 0; ip->checksum = ~checksum (ip, ip_hlen); /* redo check-sum */ ip_ofs = intel16 (ip->frag_ofs); ip_flg = ip_ofs & ~IP_OFFMASK; ip_ofs = (ip_ofs & IP_OFFMASK) << 3; /* 0 <= ip_ofs <= 65536-8 */ if (ip_ofs || (ip_flg & IP_MF)) /* fragment; let _ip_fragment() */ return (ip_len); /* handle it on next poll */ if (ip->proto == ICMP_PROTO) { ICMP_PKT *icmp = (ICMP_PKT*) ((BYTE*)ip + ip_hlen); int len = icmp_loopback (icmp, ip_len - ip_hlen); if (len > 0) return (ip_hlen+len); } else if (ip->proto == UDP_PROTO) { udp_Header *udp = (udp_Header*) ((BYTE*)ip + ip_hlen); int len = udp_loopback (udp, ip_len-ip_hlen); if (len > 0) return (ip_hlen+len); } if (loopback_handler) ip_len = (*loopback_handler) (ip); return (ip_len); }
/* * Send an "ICMP Time Exceeded" (reassebly timeout) back to 'ip->source' */ void icmp_timexceed (const in_Header *ip, const void *mac_dest) { struct _pkt *pkt; union icmp_pkt *tim; int len; if (!icmp_chk_src(ip,ICMP_TIMXCEED)) return; pkt = (struct _pkt*) _eth_formatpacket (mac_dest, IP_TYPE); tim = &pkt->icmp; len = intel16 (ip->length) - in_GetHdrLen (ip); len = min (len, sizeof(*ip) + sizeof(tim->unused.spares)); icmp_print (1, icmp_exceed_str[1], ip->destination); memcpy (&tim->unused.ip, ip, len); tim->unused.type = ICMP_TIMXCEED; tim->unused.code = 1; icmp_send (pkt, ip->destination, ip->source, sizeof(tim->unused)); }
/* * Send an ICMP destination/protocol unreachable back to ip->source */ void icmp_unreach (const in_Header *ip, int code) { struct _pkt *pkt; union icmp_pkt *unr; int len; if (!icmp_chk_src(ip,ICMP_UNREACH)) return; pkt = (struct _pkt*) _eth_formatpacket (MAC_SRC(ip), IP_TYPE); unr = &pkt->icmp; len = intel16 (ip->length) - in_GetHdrLen (ip); len = min (len, sizeof(*ip)+sizeof(unr->unused.spares)); icmp_print (1, icmp_unreach_str[code], ip->destination); memcpy (&unr->unused.ip, ip, len); unr->unused.type = ICMP_UNREACH; unr->unused.code = code; icmp_send (pkt, ip->destination, ip->source, sizeof(unr->unused)); }
/** * \def loopback_device(). * * We have been called with an IP-packet located on stack by `send_loopback()' * (in pcsed.c). Hence, it's safe to call _eth_send() again here. * MAC-header is in front of 'ip'. */ int loopback_device (in_Header *ip) { int ip_len = 0; DWORD ip_dst; DWORD ip_ofs; WORD ip_flg; if (!(loopback_mode & LBACK_MODE_ENABLE)) return (-1); if (ip->ver == 4) { int ip_hlen; if (!_chk_ip4_header(ip)) /* silently discard */ return (-1); ip_hlen = in_GetHdrLen (ip); /* length of IP-header (w/options) */ ip_len = intel16 (ip->length); /* total length of IP-packet */ ip_dst = ip->destination; ip->destination = ip->source; /* swap source and destination */ ip->source = ip_dst; ip->checksum = 0; ip->checksum = ~CHECKSUM (ip, ip_hlen); /* redo check-sum */ ip_ofs = intel16 (ip->frag_ofs); ip_flg = (WORD) (ip_ofs & ~IP_OFFMASK); ip_ofs = (ip_ofs & IP_OFFMASK) << 3; /* 0 <= ip_ofs <= 65536-8 */ if (ip_ofs || (ip_flg & IP_MF)) /* fragment; let ip4_defragment() */ return (ip_len); /* handle it on next poll */ if (ip->proto == ICMP_PROTO) { ICMP_PKT *icmp = (ICMP_PKT*) ((BYTE*)ip + ip_hlen); int len = icmp_loopback (icmp, ip_len - ip_hlen); if (len > 0) return (ip_hlen+len); } else if (ip->proto == UDP_PROTO) { udp_Header *udp = (udp_Header*) ((BYTE*)ip + ip_hlen); int len = udp_loopback (udp, ip_len-ip_hlen); if (len > 0) return (ip_hlen+len); } } #if defined(USE_IPV6) else if (ip->ver == 6) { in6_Header *ip6 = (in6_Header*)ip; ip6_address ip6_dst; ip_len = intel16 (ip6->len); memcpy (&ip6_dst, &ip6->destination, sizeof(ip6_dst)); memcpy (&ip6->destination, &ip6->source, sizeof(ip6->destination)); memcpy (&ip6->source, &ip6_dst, sizeof(ip6->source)); if (ip6->next_hdr == IP6_NEXT_ICMP) { ICMP_PKT *icmp = (ICMP_PKT*) (ip6 + 1); int len = icmp_loopback (icmp, ip_len); if (len > 0) return (len + sizeof(*ip6)); } else if (ip6->next_hdr == UDP_PROTO) { udp_Header *udp = (udp_Header*) (ip6 + 1); int len = udp_loopback (udp, ip_len); if (len > 0) return (len + sizeof(*ip6)); } } else { (*_printf) ("%s: Illegal IP-packet (ver %d) for loopback device\n", __FILE__, ip->ver); return (-1); } #endif if (loopback_handler) ip_len = (*loopback_handler) (ip); return (ip_len); }
/* * 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; } }
/** * Handler for incoming ICMP packets. */ void icmp_handler (const in_Header *ip, BOOL broadcast) { union ICMP_PKT *icmp; const in_Header *orig_ip; int type, code; unsigned len; DWORD delta_time; 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 = _ip4_is_multihome_addr (intel(ip->destination)); 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 = _ip4_is_local_addr (intel(orig_ip->source)); if (type == ICMP_MASKREPLY) { if (!_do_mask_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 */ delta_time = set_timeout(0) - icmp->echo.identifier; add_ping (intel(ip->source), delta_time, icmp->echo.index); return; case ICMP_UNREACH: if (code < DIM(icmp_unreach_str)) { UINT len_needed = 8 + in_GetHdrLen (orig_ip); WORD next_mtu = 0; msg = _LANG (icmp_unreach_str[code]); icmp_print (1, msg, ip->source); if (orig_ip->proto == TCP_PROTO || orig_ip->proto == UDP_PROTO) len_needed += 4; /* Need the src/dest port numbers */ if (len >= len_needed) { if (code == ICMP_UNREACH_NEEDFRAG) next_mtu = intel16 (icmp->needfrag.next_mtu); #if !defined(USE_UDP_ONLY) if (orig_ip->proto == TCP_PROTO) _tcp_cancel (orig_ip, ICMP_UNREACH, code, msg, &next_mtu); else #endif if (orig_ip->proto == UDP_PROTO) _udp_cancel (orig_ip, ICMP_UNREACH, code, msg, &next_mtu); /** \todo Handle cancelling raw sockets */ #if defined(USE_BSD_API) && 0 else _raw_cancel (orig_ip, ICMP_UNREACH, code, msg); #endif } else STAT (icmpstats.icps_tooshort++); } else STAT (icmpstats.icps_badcode++); return; case ICMP_SOURCEQUENCH: #if !defined(USE_UDP_ONLY) if (orig_ip->proto == TCP_PROTO) { msg = _LANG (icmp_type_str[type]); icmp_print (1, msg, ip->source); _tcp_cancel (orig_ip, ICMP_SOURCEQUENCH, code, msg, NULL); } #endif return; case ICMP_REDIRECT: if (code < DIM(icmp_redirect_str)) icmp_redirect (icmp, ip, orig_ip, code); else STAT (icmpstats.icps_badcode++); return; case ICMP_ECHO: icmp_print (2, _LANG("PING requested of us"), ip->source); icmp_echo_reply (ip, icmp, len); return; case ICMP_TIMXCEED: if (code >= DIM(icmp_exceed_str)) { STAT (icmpstats.icps_badcode++); return; } if (code == 0) /* "TTL exceeded in transit" */ switch (orig_ip->proto) { #if !defined(USE_UDP_ONLY) case TCP_PROTO: msg = _LANG (icmp_exceed_str[0]); icmp_print (1, msg, ip->source); _tcp_cancel (orig_ip, ICMP_TIMXCEED, code, msg, NULL); break; #endif case UDP_PROTO: msg = _LANG (icmp_exceed_str[0]); icmp_print (1, msg, ip->source); _udp_cancel (orig_ip, ICMP_TIMXCEED, code, msg, NULL); break; } return; case ICMP_PARAMPROB: msg = _LANG (icmp_type_str[ICMP_PARAMPROB]); switch (orig_ip->proto) { #if !defined(USE_UDP_ONLY) case TCP_PROTO: icmp_print (0, msg, ip->source); _tcp_cancel (orig_ip, ICMP_PARAMPROB, code, msg, NULL); break; #endif case UDP_PROTO: icmp_print (0, msg, ip->source); _udp_cancel (orig_ip, ICMP_PARAMPROB, code, msg, NULL); break; } return; case ICMP_ROUTERADVERT: /* todo !! */ msg = _LANG (icmp_type_str[ICMP_ROUTERADVERT]); icmp_print (1, msg, ip->source); return; case ICMP_ROUTERSOLICIT: /* todo !! */ msg = _LANG (icmp_type_str[ICMP_ROUTERSOLICIT]); icmp_print (1, msg, ip->source); return; case ICMP_TSTAMP: msg = _LANG (icmp_type_str[ICMP_TSTAMP]); icmp_print (1, msg, ip->source); /**< \todo send reply? */ return; case ICMP_TSTAMPREPLY: msg = _LANG (icmp_type_str[ICMP_TSTAMPREPLY]); icmp_print (1, msg, ip->source); /**< \todo should store */ return; case ICMP_IREQ: msg = _LANG (icmp_type_str[ICMP_IREQ]); icmp_print (1, msg, ip->source); /**< \todo send reply */ return; case ICMP_IREQREPLY: msg = _LANG (icmp_type_str[ICMP_IREQREPLY]); icmp_print (1, msg, ip->source); /**< \todo send reply upwards */ return; case ICMP_MASKREQ: /* might be sent by us, never answer */ break; case ICMP_MASKREPLY: msg = _LANG (icmp_type_str[ICMP_MASKREPLY]); icmp_print (0, msg, 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; } }