📄 icmp.c
字号:
/*icmp.cCopyright 1995 Philip Homburg*/#include "inet.h"#include "buf.h"#include "event.h"#include "type.h"#include "assert.h"#include "clock.h"#include "icmp.h"#include "icmp_lib.h"#include "io.h"#include "ip.h"#include "ip_int.h"#include "ipr.h"THIS_FILEtypedef struct icmp_port{ int icp_flags; int icp_state; int icp_ipport; int icp_ipfd; unsigned icp_rate_count; unsigned icp_rate_report; time_t icp_rate_lasttime; acc_t *icp_head_queue; acc_t *icp_tail_queue; acc_t *icp_write_pack; event_t icp_event;} icmp_port_t;#define ICPF_EMPTY 0x0#define ICPF_SUSPEND 0x1#define ICPF_READ_IP 0x2#define ICPF_READ_SP 0x4#define ICPF_WRITE_IP 0x8#define ICPF_WRITE_SP 0x10#define ICPS_BEGIN 0#define ICPS_IPOPT 1#define ICPS_MAIN 2#define ICPS_ERROR 3PRIVATE icmp_port_t *icmp_port_table;FORWARD void icmp_main ARGS(( icmp_port_t *icmp_port ));FORWARD acc_t *icmp_getdata ARGS(( int port, size_t offset, size_t count, int for_ioctl ));FORWARD int icmp_putdata ARGS(( int port, size_t offset, acc_t *data, int for_ioctl ));FORWARD void icmp_read ARGS(( icmp_port_t *icmp_port ));FORWARD void process_data ARGS(( icmp_port_t *icmp_port, acc_t *data ));FORWARD u16_t icmp_pack_oneCsum ARGS(( acc_t *ip_pack ));FORWARD void icmp_echo_request ARGS(( icmp_port_t *icmp_port, acc_t *ip_pack, int ip_hdr_len, ip_hdr_t *ip_hdr, acc_t *icmp_pack, int icmp_len, icmp_hdr_t *icmp_hdr ));FORWARD void icmp_dst_unreach ARGS(( icmp_port_t *icmp_port, acc_t *ip_pack, int ip_hdr_len, ip_hdr_t *ip_hdr, acc_t *icmp_pack, int icmp_len, icmp_hdr_t *icmp_hdr ));FORWARD void icmp_time_exceeded ARGS(( icmp_port_t *icmp_port, acc_t *ip_pack, int ip_hdr_len, ip_hdr_t *ip_hdr, acc_t *icmp_pack, int icmp_len, icmp_hdr_t *icmp_hdr ));FORWARD void icmp_router_advertisement ARGS(( icmp_port_t *icmp_port, acc_t *icmp_pack, int icmp_len, icmp_hdr_t *icmp_hdr ));FORWARD void icmp_redirect ARGS(( icmp_port_t *icmp_port, ip_hdr_t *ip_hdr, acc_t *icmp_pack, int icmp_len, icmp_hdr_t *icmp_hdr ));FORWARD acc_t *make_repl_ip ARGS(( ip_hdr_t *ip_hdr, int ip_len ));FORWARD void enqueue_pack ARGS(( icmp_port_t *icmp_port, acc_t *reply_ip_hdr ));FORWARD int icmp_rate_limit ARGS(( icmp_port_t *icmp_port, acc_t *reply_ip_hdr ));FORWARD void icmp_write ARGS(( event_t *ev, ev_arg_t ev_arg ));FORWARD void icmp_buffree ARGS(( int priority ));FORWARD acc_t *icmp_err_pack ARGS(( acc_t *pack, icmp_hdr_t **icmp_hdr_pp ));#ifdef BUF_CONSISTENCY_CHECKFORWARD void icmp_bufcheck ARGS(( void ));#endifPUBLIC void icmp_prep(){ icmp_port_table= alloc(ip_conf_nr * sizeof(icmp_port_table[0]));}PUBLIC void icmp_init(){ int i; icmp_port_t *icmp_port; assert (BUF_S >= sizeof (nwio_ipopt_t)); for (i= 0, icmp_port= icmp_port_table; i<ip_conf_nr; i++, icmp_port++) { icmp_port->icp_flags= ICPF_EMPTY; icmp_port->icp_state= ICPS_BEGIN; icmp_port->icp_ipport= i; icmp_port->icp_rate_count= 0; icmp_port->icp_rate_report= ICMP_MAX_RATE; icmp_port->icp_rate_lasttime= 0; ev_init(&icmp_port->icp_event); }#ifndef BUF_CONSISTENCY_CHECK bf_logon(icmp_buffree);#else bf_logon(icmp_buffree, icmp_bufcheck);#endif for (i= 0, icmp_port= icmp_port_table; i<ip_conf_nr; i++, icmp_port++) { icmp_main (icmp_port); }}PRIVATE void icmp_main(icmp_port)icmp_port_t *icmp_port;{ int result; switch (icmp_port->icp_state) { case ICPS_BEGIN: icmp_port->icp_head_queue= 0; icmp_port->icp_ipfd= ip_open(icmp_port->icp_ipport, icmp_port->icp_ipport, icmp_getdata, icmp_putdata, 0 /* no put_pkt */, 0 /* no select_res */); if (icmp_port->icp_ipfd<0) { DBLOCK(1, printf("unable to open ip_port %d\n", icmp_port->icp_ipport)); break; } icmp_port->icp_state= ICPS_IPOPT; icmp_port->icp_flags &= ~ICPF_SUSPEND; result= ip_ioctl (icmp_port->icp_ipfd, NWIOSIPOPT); if (result == NW_SUSPEND) { icmp_port->icp_flags |= ICPF_SUSPEND; break; } assert(result == NW_OK); /* falls through */ case ICPS_IPOPT: icmp_port->icp_state= ICPS_MAIN; icmp_port->icp_flags &= ~ICPF_SUSPEND; icmp_read(icmp_port); break; default: DBLOCK(1, printf("unknown state %d\n", icmp_port->icp_state)); break; }}PRIVATE acc_t *icmp_getdata(port, offset, count, for_ioctl)int port;size_t offset, count;int for_ioctl;{ icmp_port_t *icmp_port; nwio_ipopt_t *ipopt; acc_t *data; int result; ev_arg_t ev_arg; icmp_port= &icmp_port_table[port]; if (icmp_port->icp_flags & ICPF_WRITE_IP) { if (!count) { bf_afree(icmp_port->icp_write_pack); icmp_port->icp_write_pack= 0; result= (int)offset; if (result<0) { DBLOCK(1, printf("got write error %d\n", result)); } if (icmp_port->icp_flags & ICPF_WRITE_SP) { icmp_port->icp_flags &= ~ICPF_WRITE_SP; ev_arg.ev_ptr= icmp_port; ev_enqueue(&icmp_port->icp_event, icmp_write, ev_arg); } return NW_OK; } return bf_cut(icmp_port->icp_write_pack, offset, count); } switch (icmp_port->icp_state) { case ICPS_IPOPT: if (!count) { result= (int)offset; assert(result == NW_OK); if (result < 0) { icmp_port->icp_state= ICPS_ERROR; break; } if (icmp_port->icp_flags & ICPF_SUSPEND) icmp_main(icmp_port); return NW_OK; } data= bf_memreq (sizeof (*ipopt)); ipopt= (nwio_ipopt_t *)ptr2acc_data(data); ipopt->nwio_flags= NWIO_COPY | NWIO_EN_LOC | NWIO_EN_BROAD | NWIO_REMANY | NWIO_PROTOSPEC | NWIO_HDR_O_ANY | NWIO_RWDATALL; ipopt->nwio_proto= IPPROTO_ICMP; return data; default: break; } DBLOCK(1, printf("unknown state %d\n", icmp_port->icp_state)); return NULL;}PRIVATE int icmp_putdata(port, offset, data, for_ioctl)int port;size_t offset;acc_t *data;int for_ioctl;{ icmp_port_t *icmp_port; int result; icmp_port= &icmp_port_table[port]; if (icmp_port->icp_flags & ICPF_READ_IP) { if (!data) { result= (int)offset; if (result<0) { DBLOCK(1, printf("got read error %d\n", result)); } if (icmp_port->icp_flags & ICPF_READ_SP) { icmp_port->icp_flags &= ~(ICPF_READ_IP|ICPF_READ_SP); icmp_read (icmp_port); } return NW_OK; } process_data(icmp_port, data); return NW_OK; } switch (icmp_port->icp_state) { default: DBLOCK(1, printf("unknown state %d\n", icmp_port->icp_state)); return 0; }}PRIVATE void icmp_read(icmp_port)icmp_port_t *icmp_port;{ int result; for (;;) { icmp_port->icp_flags |= ICPF_READ_IP; icmp_port->icp_flags &= ~ICPF_READ_SP; result= ip_read(icmp_port->icp_ipfd, ICMP_MAX_DATAGRAM); if (result == NW_SUSPEND) { icmp_port->icp_flags |= ICPF_READ_SP; return; } }}PUBLIC void icmp_snd_time_exceeded(port_nr, pack, code)int port_nr;acc_t *pack;int code;{ icmp_hdr_t *icmp_hdr; icmp_port_t *icmp_port; if (port_nr >= 0 && port_nr < ip_conf_nr) icmp_port= &icmp_port_table[port_nr]; else { printf("icmp_snd_time_exceeded: strange port %d\n", port_nr); bf_afree(pack); return; } pack= icmp_err_pack(pack, &icmp_hdr); if (pack == NULL) return; icmp_hdr->ih_type= ICMP_TYPE_TIME_EXCEEDED; icmp_hdr->ih_code= code; icmp_hdr->ih_chksum= ~oneC_sum(~icmp_hdr->ih_chksum, (u16_t *)&icmp_hdr->ih_type, 2); enqueue_pack(icmp_port, pack);}PUBLIC void icmp_snd_redirect(port_nr, pack, code, gw)int port_nr;acc_t *pack;int code;ipaddr_t gw;{ icmp_hdr_t *icmp_hdr; icmp_port_t *icmp_port; if (port_nr >= 0 && port_nr < ip_conf_nr) icmp_port= &icmp_port_table[port_nr]; else { printf("icmp_snd_redirect: strange port %d\n", port_nr); bf_afree(pack); return; } pack= icmp_err_pack(pack, &icmp_hdr); if (pack == NULL) return; icmp_hdr->ih_type= ICMP_TYPE_REDIRECT; icmp_hdr->ih_code= code; icmp_hdr->ih_hun.ihh_gateway= gw; icmp_hdr->ih_chksum= ~oneC_sum(~icmp_hdr->ih_chksum, (u16_t *)&icmp_hdr->ih_type, 2); icmp_hdr->ih_chksum= ~oneC_sum(~icmp_hdr->ih_chksum, (u16_t *)&icmp_hdr->ih_hun.ihh_gateway, 4); enqueue_pack(icmp_port, pack);}PUBLIC void icmp_snd_unreachable(port_nr, pack, code)int port_nr;acc_t *pack;int code;{ icmp_hdr_t *icmp_hdr; icmp_port_t *icmp_port; if (port_nr >= 0 && port_nr < ip_conf_nr) icmp_port= &icmp_port_table[port_nr]; else { printf("icmp_snd_unreachable: strange port %d\n", port_nr); bf_afree(pack); return; } pack= icmp_err_pack(pack, &icmp_hdr); if (pack == NULL) return; icmp_hdr->ih_type= ICMP_TYPE_DST_UNRCH; icmp_hdr->ih_code= code; icmp_hdr->ih_chksum= ~oneC_sum(~icmp_hdr->ih_chksum, (u16_t *)&icmp_hdr->ih_type, 2); enqueue_pack(icmp_port, pack);}PUBLIC void icmp_snd_mtu(port_nr, pack, mtu)int port_nr;acc_t *pack;u16_t mtu;{ icmp_hdr_t *icmp_hdr; icmp_port_t *icmp_port; if (port_nr >= 0 && port_nr < ip_conf_nr) icmp_port= &icmp_port_table[port_nr]; else { printf("icmp_snd_mtu: strange port %d\n", port_nr); bf_afree(pack); return; } pack= icmp_err_pack(pack, &icmp_hdr); if (pack == NULL) return; icmp_hdr->ih_type= ICMP_TYPE_DST_UNRCH; icmp_hdr->ih_code= ICMP_FRAGM_AND_DF; icmp_hdr->ih_hun.ihh_mtu.im_mtu= htons(mtu); icmp_hdr->ih_chksum= ~oneC_sum(~icmp_hdr->ih_chksum, (u16_t *)&icmp_hdr->ih_type, 2); icmp_hdr->ih_chksum= ~oneC_sum(~icmp_hdr->ih_chksum, (u16_t *)&icmp_hdr->ih_hun.ihh_mtu.im_mtu, 2); enqueue_pack(icmp_port, pack);}PRIVATE void process_data(icmp_port, data)icmp_port_t *icmp_port;acc_t *data;{ ip_hdr_t *ip_hdr; icmp_hdr_t *icmp_hdr; acc_t *icmp_data; int ip_hdr_len; size_t pack_len; /* Align entire packet */ data= bf_align(data, BUF_S, 4); data= bf_packIffLess(data, IP_MIN_HDR_SIZE); ip_hdr= (ip_hdr_t *)ptr2acc_data(data); DIFBLOCK(0x10, (ip_hdr->ih_dst & HTONL(0xf0000000)) == HTONL(0xe0000000), printf("got multicast packet\n")); ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2; if (ip_hdr_len>IP_MIN_HDR_SIZE) { data= bf_packIffLess(data, ip_hdr_len); ip_hdr= (ip_hdr_t *)ptr2acc_data(data); } pack_len= bf_bufsize(data); pack_len -= ip_hdr_len; if (pack_len < ICMP_MIN_HDR_SIZE) { if (pack_len == 0 && ip_hdr->ih_proto == 0) { /* IP layer reports new ip address, which can be * ignored. */ } else DBLOCK(1, printf("got an incomplete icmp packet\n")); bf_afree(data); return; } icmp_data= bf_cut(data, ip_hdr_len, pack_len); icmp_data= bf_packIffLess (icmp_data, ICMP_MIN_HDR_SIZE); icmp_hdr= (icmp_hdr_t *)ptr2acc_data(icmp_data); if ((u16_t)~icmp_pack_oneCsum(icmp_data)) { DBLOCK(1, printf( "got packet with bad checksum (= 0x%x, 0x%x)\n", icmp_hdr->ih_chksum, (u16_t)~icmp_pack_oneCsum(icmp_data))); bf_afree(data); bf_afree(icmp_data); return; } switch (icmp_hdr->ih_type) { case ICMP_TYPE_ECHO_REPL: break; case ICMP_TYPE_DST_UNRCH: icmp_dst_unreach (icmp_port, data, ip_hdr_len, ip_hdr, icmp_data, pack_len, icmp_hdr); break; case ICMP_TYPE_SRC_QUENCH: /* Ignore src quench ICMPs */ DBLOCK(2, printf("ignoring SRC QUENCH ICMP.\n")); break; case ICMP_TYPE_REDIRECT: icmp_redirect (icmp_port, ip_hdr, icmp_data, pack_len, icmp_hdr); break; case ICMP_TYPE_ECHO_REQ: icmp_echo_request(icmp_port, data, ip_hdr_len, ip_hdr, icmp_data, pack_len, icmp_hdr); return; case ICMP_TYPE_ROUTER_ADVER: icmp_router_advertisement(icmp_port, icmp_data, pack_len, icmp_hdr); break; case ICMP_TYPE_ROUTE_SOL: break; /* Should be handled by a routing deamon. */ case ICMP_TYPE_TIME_EXCEEDED: icmp_time_exceeded (icmp_port, data, ip_hdr_len, ip_hdr, icmp_data, pack_len, icmp_hdr); break; default: DBLOCK(1, printf("got an unknown icmp (%d) from ", icmp_hdr->ih_type); writeIpAddr(ip_hdr->ih_src); printf("\n")); break; } bf_afree(data); bf_afree(icmp_data);}PRIVATE void icmp_echo_request(icmp_port, ip_data, ip_len, ip_hdr, icmp_data, icmp_len, icmp_hdr)icmp_port_t *icmp_port;acc_t *ip_data, *icmp_data;int ip_len, icmp_len;ip_hdr_t *ip_hdr;icmp_hdr_t *icmp_hdr;{ acc_t *repl_ip_hdr, *repl_icmp; ipaddr_t tmpaddr, locaddr, netmask; icmp_hdr_t *repl_icmp_hdr; i32_t tmp_chksum; ip_port_t *ip_port; if (icmp_hdr->ih_code != 0) { DBLOCK(1, printf("got an icmp echo request with unknown code (%d)\n", icmp_hdr->ih_code)); bf_afree(ip_data); bf_afree(icmp_data); return; } if (icmp_len < ICMP_MIN_HDR_SIZE + sizeof(icmp_id_seq_t)) { DBLOCK(1, printf("got an incomplete icmp echo request\n")); bf_afree(ip_data); bf_afree(icmp_data); return; } tmpaddr= ntohl(ip_hdr->ih_dst); if ((tmpaddr & 0xe0000000) == 0xe0000000 && tmpaddr != 0xffffffff) { /* Respond only to the all hosts multicast address until * a decent listening service has been implemented */ if (tmpaddr != 0xe0000001) { bf_afree(ip_data); bf_afree(icmp_data); return; } } /* Limit subnet broadcasts to the local net */ ip_port= &ip_port_table[icmp_port->icp_ipport]; locaddr= ip_port->ip_ipaddr; netmask= ip_port->ip_subnetmask; if (ip_hdr->ih_dst == (locaddr | ~netmask) && (ip_port->ip_flags & IPF_SUBNET_BCAST) && ((ip_hdr->ih_src ^ locaddr) & netmask) != 0) { /* Directed broadcast */ bf_afree(ip_data); bf_afree(icmp_data); return; } repl_ip_hdr= make_repl_ip(ip_hdr, ip_len); repl_icmp= bf_memreq (ICMP_MIN_HDR_SIZE); repl_icmp_hdr= (icmp_hdr_t *)ptr2acc_data(repl_icmp); repl_icmp_hdr->ih_type= ICMP_TYPE_ECHO_REPL; repl_icmp_hdr->ih_code= 0; DBLOCK(2, printf("ih_chksum= 0x%x, ih_type= 0x%x, repl->ih_type= 0x%x\n", icmp_hdr->ih_chksum, *(u16_t *)&icmp_hdr->ih_type, *(u16_t *)&repl_icmp_hdr->ih_type)); tmp_chksum= (~icmp_hdr->ih_chksum & 0xffff) - (i32_t)*(u16_t *)&icmp_hdr->ih_type+ *(u16_t *)&repl_icmp_hdr->ih_type; tmp_chksum= (tmp_chksum >> 16) + (tmp_chksum & 0xffff); tmp_chksum= (tmp_chksum >> 16) + (tmp_chksum & 0xffff); repl_icmp_hdr->ih_chksum= ~tmp_chksum; DBLOCK(2, printf("sending chksum 0x%x\n", repl_icmp_hdr->ih_chksum)); repl_ip_hdr->acc_next= repl_icmp; repl_icmp->acc_next= bf_cut (icmp_data, ICMP_MIN_HDR_SIZE, icmp_len - ICMP_MIN_HDR_SIZE); bf_afree(ip_data); bf_afree(icmp_data); enqueue_pack(icmp_port, repl_ip_hdr);}PRIVATE u16_t icmp_pack_oneCsum(icmp_pack)acc_t *icmp_pack;{ u16_t prev; int odd_byte; char *data_ptr; int length; char byte_buf[2]; prev= 0; odd_byte= FALSE; for (; icmp_pack; icmp_pack= icmp_pack->acc_next) { data_ptr= ptr2acc_data(icmp_pack); length= icmp_pack->acc_length; if (!length) continue; if (odd_byte) { byte_buf[1]= *data_ptr; prev= oneC_sum(prev, (u16_t *)byte_buf, 2); data_ptr++; length--; odd_byte= FALSE; } if (length & 1)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -