4 Copyright 1995 Philip Homburg
23 typedef struct icmp_port
29 unsigned icp_rate_count
;
30 unsigned icp_rate_report
;
31 time_t icp_rate_lasttime
;
32 acc_t
*icp_head_queue
;
33 acc_t
*icp_tail_queue
;
34 acc_t
*icp_write_pack
;
38 #define ICPF_EMPTY 0x0
39 #define ICPF_SUSPEND 0x1
40 #define ICPF_READ_IP 0x2
41 #define ICPF_READ_SP 0x4
42 #define ICPF_WRITE_IP 0x8
43 #define ICPF_WRITE_SP 0x10
50 static icmp_port_t
*icmp_port_table
;
52 static void icmp_main
ARGS(( icmp_port_t
*icmp_port
));
53 static acc_t
*icmp_getdata
ARGS(( int port
, size_t offset
,
54 size_t count
, int for_ioctl
));
55 static int icmp_putdata
ARGS(( int port
, size_t offset
,
56 acc_t
*data
, int for_ioctl
));
57 static void icmp_read
ARGS(( icmp_port_t
*icmp_port
));
58 static void process_data
ARGS(( icmp_port_t
*icmp_port
,
60 static u16_t icmp_pack_oneCsum
ARGS(( acc_t
*ip_pack
));
61 static void icmp_echo_request
ARGS(( icmp_port_t
*icmp_port
,
62 acc_t
*ip_pack
, int ip_hdr_len
, ip_hdr_t
*ip_hdr
,
63 acc_t
*icmp_pack
, int icmp_len
, icmp_hdr_t
*icmp_hdr
));
64 static void icmp_dst_unreach
ARGS(( icmp_port_t
*icmp_port
,
65 acc_t
*ip_pack
, int ip_hdr_len
, ip_hdr_t
*ip_hdr
,
66 acc_t
*icmp_pack
, int icmp_len
, icmp_hdr_t
*icmp_hdr
));
67 static void icmp_time_exceeded
ARGS(( icmp_port_t
*icmp_port
,
68 acc_t
*ip_pack
, int ip_hdr_len
, ip_hdr_t
*ip_hdr
,
69 acc_t
*icmp_pack
, int icmp_len
, icmp_hdr_t
*icmp_hdr
));
70 static void icmp_router_advertisement
ARGS(( icmp_port_t
*icmp_port
,
71 acc_t
*icmp_pack
, int icmp_len
, icmp_hdr_t
*icmp_hdr
));
72 static void icmp_redirect
ARGS(( icmp_port_t
*icmp_port
,
73 ip_hdr_t
*ip_hdr
, acc_t
*icmp_pack
, int icmp_len
,
74 icmp_hdr_t
*icmp_hdr
));
75 static acc_t
*make_repl_ip
ARGS(( ip_hdr_t
*ip_hdr
,
77 static void enqueue_pack
ARGS(( icmp_port_t
*icmp_port
,
78 acc_t
*reply_ip_hdr
));
79 static int icmp_rate_limit
ARGS(( icmp_port_t
*icmp_port
,
80 acc_t
*reply_ip_hdr
));
81 static void icmp_write
ARGS(( event_t
*ev
, ev_arg_t ev_arg
));
82 static void icmp_buffree
ARGS(( int priority
));
83 static acc_t
*icmp_err_pack
ARGS(( acc_t
*pack
, icmp_hdr_t
**icmp_hdr_pp
));
84 #ifdef BUF_CONSISTENCY_CHECK
85 static void icmp_bufcheck
ARGS(( void ));
90 icmp_port_table
= alloc(ip_conf_nr
* sizeof(icmp_port_table
[0]));
96 icmp_port_t
*icmp_port
;
98 assert (BUF_S
>= sizeof (nwio_ipopt_t
));
100 for (i
= 0, icmp_port
= icmp_port_table
; i
<ip_conf_nr
; i
++, icmp_port
++)
102 icmp_port
->icp_flags
= ICPF_EMPTY
;
103 icmp_port
->icp_state
= ICPS_BEGIN
;
104 icmp_port
->icp_ipport
= i
;
105 icmp_port
->icp_rate_count
= 0;
106 icmp_port
->icp_rate_report
= ICMP_MAX_RATE
;
107 icmp_port
->icp_rate_lasttime
= 0;
108 ev_init(&icmp_port
->icp_event
);
111 #ifndef BUF_CONSISTENCY_CHECK
112 bf_logon(icmp_buffree
);
114 bf_logon(icmp_buffree
, icmp_bufcheck
);
117 for (i
= 0, icmp_port
= icmp_port_table
; i
<ip_conf_nr
; i
++, icmp_port
++)
119 icmp_main (icmp_port
);
123 static void icmp_main(icmp_port
)
124 icmp_port_t
*icmp_port
;
127 switch (icmp_port
->icp_state
)
130 icmp_port
->icp_head_queue
= 0;
131 icmp_port
->icp_ipfd
= ip_open(icmp_port
->icp_ipport
,
132 icmp_port
->icp_ipport
, icmp_getdata
, icmp_putdata
,
133 0 /* no put_pkt */, 0 /* no select_res */);
134 if (icmp_port
->icp_ipfd
<0)
136 DBLOCK(1, printf("unable to open ip_port %d\n",
137 icmp_port
->icp_ipport
));
140 icmp_port
->icp_state
= ICPS_IPOPT
;
141 icmp_port
->icp_flags
&= ~ICPF_SUSPEND
;
142 result
= ip_ioctl (icmp_port
->icp_ipfd
, NWIOSIPOPT
);
143 if (result
== NW_SUSPEND
)
145 icmp_port
->icp_flags
|= ICPF_SUSPEND
;
148 assert(result
== NW_OK
);
152 icmp_port
->icp_state
= ICPS_MAIN
;
153 icmp_port
->icp_flags
&= ~ICPF_SUSPEND
;
154 icmp_read(icmp_port
);
157 DBLOCK(1, printf("unknown state %d\n",
158 icmp_port
->icp_state
));
163 static acc_t
*icmp_getdata(port
, offset
, count
, for_ioctl
)
165 size_t offset
, count
;
168 icmp_port_t
*icmp_port
;
174 icmp_port
= &icmp_port_table
[port
];
176 if (icmp_port
->icp_flags
& ICPF_WRITE_IP
)
180 bf_afree(icmp_port
->icp_write_pack
);
181 icmp_port
->icp_write_pack
= 0;
186 DBLOCK(1, printf("got write error %d\n",
189 if (icmp_port
->icp_flags
& ICPF_WRITE_SP
)
191 icmp_port
->icp_flags
&= ~ICPF_WRITE_SP
;
192 ev_arg
.ev_ptr
= icmp_port
;
193 ev_enqueue(&icmp_port
->icp_event
, icmp_write
,
198 return bf_cut(icmp_port
->icp_write_pack
, offset
, count
);
200 switch (icmp_port
->icp_state
)
206 assert(result
== NW_OK
);
209 icmp_port
->icp_state
= ICPS_ERROR
;
212 if (icmp_port
->icp_flags
& ICPF_SUSPEND
)
213 icmp_main(icmp_port
);
217 data
= bf_memreq (sizeof (*ipopt
));
218 ipopt
= (nwio_ipopt_t
*)ptr2acc_data(data
);
219 ipopt
->nwio_flags
= NWIO_COPY
| NWIO_EN_LOC
|
221 NWIO_REMANY
| NWIO_PROTOSPEC
|
222 NWIO_HDR_O_ANY
| NWIO_RWDATALL
;
223 ipopt
->nwio_proto
= IPPROTO_ICMP
;
228 DBLOCK(1, printf("unknown state %d\n", icmp_port
->icp_state
));
232 static int icmp_putdata(port
, offset
, data
, for_ioctl
)
238 icmp_port_t
*icmp_port
;
241 icmp_port
= &icmp_port_table
[port
];
243 if (icmp_port
->icp_flags
& ICPF_READ_IP
)
250 DBLOCK(1, printf("got read error %d\n",
253 if (icmp_port
->icp_flags
& ICPF_READ_SP
)
255 icmp_port
->icp_flags
&=
256 ~(ICPF_READ_IP
|ICPF_READ_SP
);
257 icmp_read (icmp_port
);
261 process_data(icmp_port
, data
);
264 switch (icmp_port
->icp_state
)
267 DBLOCK(1, printf("unknown state %d\n",
268 icmp_port
->icp_state
));
273 static void icmp_read(icmp_port
)
274 icmp_port_t
*icmp_port
;
280 icmp_port
->icp_flags
|= ICPF_READ_IP
;
281 icmp_port
->icp_flags
&= ~ICPF_READ_SP
;
283 result
= ip_read(icmp_port
->icp_ipfd
, ICMP_MAX_DATAGRAM
);
284 if (result
== NW_SUSPEND
)
286 icmp_port
->icp_flags
|= ICPF_READ_SP
;
292 void icmp_snd_time_exceeded(port_nr
, pack
, code
)
297 icmp_hdr_t
*icmp_hdr
;
298 icmp_port_t
*icmp_port
;
300 if (port_nr
>= 0 && port_nr
< ip_conf_nr
)
301 icmp_port
= &icmp_port_table
[port_nr
];
304 printf("icmp_snd_time_exceeded: strange port %d\n", port_nr
);
308 pack
= icmp_err_pack(pack
, &icmp_hdr
);
311 icmp_hdr
->ih_type
= ICMP_TYPE_TIME_EXCEEDED
;
312 icmp_hdr
->ih_code
= code
;
313 icmp_hdr
->ih_chksum
= ~oneC_sum(~icmp_hdr
->ih_chksum
,
314 (u16_t
*)&icmp_hdr
->ih_type
, 2);
315 enqueue_pack(icmp_port
, pack
);
318 void icmp_snd_redirect(port_nr
, pack
, code
, gw
)
324 icmp_hdr_t
*icmp_hdr
;
325 icmp_port_t
*icmp_port
;
327 if (port_nr
>= 0 && port_nr
< ip_conf_nr
)
328 icmp_port
= &icmp_port_table
[port_nr
];
331 printf("icmp_snd_redirect: strange port %d\n", port_nr
);
335 pack
= icmp_err_pack(pack
, &icmp_hdr
);
338 icmp_hdr
->ih_type
= ICMP_TYPE_REDIRECT
;
339 icmp_hdr
->ih_code
= code
;
340 icmp_hdr
->ih_hun
.ihh_gateway
= gw
;
341 icmp_hdr
->ih_chksum
= ~oneC_sum(~icmp_hdr
->ih_chksum
,
342 (u16_t
*)&icmp_hdr
->ih_type
, 2);
343 icmp_hdr
->ih_chksum
= ~oneC_sum(~icmp_hdr
->ih_chksum
,
344 (u16_t
*)&icmp_hdr
->ih_hun
.ihh_gateway
, 4);
345 enqueue_pack(icmp_port
, pack
);
348 void icmp_snd_unreachable(port_nr
, pack
, code
)
353 icmp_hdr_t
*icmp_hdr
;
354 icmp_port_t
*icmp_port
;
356 if (port_nr
>= 0 && port_nr
< ip_conf_nr
)
357 icmp_port
= &icmp_port_table
[port_nr
];
360 printf("icmp_snd_unreachable: strange port %d\n", port_nr
);
364 pack
= icmp_err_pack(pack
, &icmp_hdr
);
367 icmp_hdr
->ih_type
= ICMP_TYPE_DST_UNRCH
;
368 icmp_hdr
->ih_code
= code
;
369 icmp_hdr
->ih_chksum
= ~oneC_sum(~icmp_hdr
->ih_chksum
,
370 (u16_t
*)&icmp_hdr
->ih_type
, 2);
371 enqueue_pack(icmp_port
, pack
);
380 icmp_hdr_t
*icmp_hdr
;
381 icmp_port_t
*icmp_port
;
383 if (port_nr
>= 0 && port_nr
< ip_conf_nr
)
384 icmp_port
= &icmp_port_table
[port_nr
];
387 printf("icmp_snd_mtu: strange port %d\n", port_nr
);
392 pack
= icmp_err_pack(pack
, &icmp_hdr
);
395 icmp_hdr
->ih_type
= ICMP_TYPE_DST_UNRCH
;
396 icmp_hdr
->ih_code
= ICMP_FRAGM_AND_DF
;
397 icmp_hdr
->ih_hun
.ihh_mtu
.im_mtu
= htons(mtu
);
398 icmp_hdr
->ih_chksum
= ~oneC_sum(~icmp_hdr
->ih_chksum
,
399 (u16_t
*)&icmp_hdr
->ih_type
, 2);
400 icmp_hdr
->ih_chksum
= ~oneC_sum(~icmp_hdr
->ih_chksum
,
401 (u16_t
*)&icmp_hdr
->ih_hun
.ihh_mtu
.im_mtu
, 2);
402 enqueue_pack(icmp_port
, pack
);
405 static void process_data(icmp_port
, data
)
406 icmp_port_t
*icmp_port
;
410 icmp_hdr_t
*icmp_hdr
;
415 /* Align entire packet */
416 data
= bf_align(data
, BUF_S
, 4);
418 data
= bf_packIffLess(data
, IP_MIN_HDR_SIZE
);
419 ip_hdr
= (ip_hdr_t
*)ptr2acc_data(data
);
420 DIFBLOCK(0x10, (ip_hdr
->ih_dst
& HTONL(0xf0000000)) == HTONL(0xe0000000),
421 printf("got multicast packet\n"));
422 ip_hdr_len
= (ip_hdr
->ih_vers_ihl
& IH_IHL_MASK
) << 2;
424 if (ip_hdr_len
>IP_MIN_HDR_SIZE
)
426 data
= bf_packIffLess(data
, ip_hdr_len
);
427 ip_hdr
= (ip_hdr_t
*)ptr2acc_data(data
);
430 pack_len
= bf_bufsize(data
);
431 pack_len
-= ip_hdr_len
;
432 if (pack_len
< ICMP_MIN_HDR_SIZE
)
434 if (pack_len
== 0 && ip_hdr
->ih_proto
== 0)
436 /* IP layer reports new ip address, which can be
441 DBLOCK(1, printf("got an incomplete icmp packet\n"));
446 icmp_data
= bf_cut(data
, ip_hdr_len
, pack_len
);
448 icmp_data
= bf_packIffLess (icmp_data
, ICMP_MIN_HDR_SIZE
);
449 icmp_hdr
= (icmp_hdr_t
*)ptr2acc_data(icmp_data
);
451 if ((u16_t
)~icmp_pack_oneCsum(icmp_data
))
454 "got packet with bad checksum (= 0x%x, 0x%x)\n",
456 (u16_t
)~icmp_pack_oneCsum(icmp_data
)));
462 switch (icmp_hdr
->ih_type
)
464 case ICMP_TYPE_ECHO_REPL
:
466 case ICMP_TYPE_DST_UNRCH
:
467 icmp_dst_unreach (icmp_port
, data
, ip_hdr_len
, ip_hdr
,
468 icmp_data
, pack_len
, icmp_hdr
);
470 case ICMP_TYPE_SRC_QUENCH
:
471 /* Ignore src quench ICMPs */
472 DBLOCK(2, printf("ignoring SRC QUENCH ICMP.\n"));
474 case ICMP_TYPE_REDIRECT
:
475 icmp_redirect (icmp_port
, ip_hdr
, icmp_data
, pack_len
,
478 case ICMP_TYPE_ECHO_REQ
:
479 icmp_echo_request(icmp_port
, data
, ip_hdr_len
, ip_hdr
,
480 icmp_data
, pack_len
, icmp_hdr
);
482 case ICMP_TYPE_ROUTER_ADVER
:
483 icmp_router_advertisement(icmp_port
, icmp_data
, pack_len
,
486 case ICMP_TYPE_ROUTE_SOL
:
487 break; /* Should be handled by a routing deamon. */
488 case ICMP_TYPE_TIME_EXCEEDED
:
489 icmp_time_exceeded (icmp_port
, data
, ip_hdr_len
, ip_hdr
,
490 icmp_data
, pack_len
, icmp_hdr
);
493 DBLOCK(1, printf("got an unknown icmp (%d) from ",
495 writeIpAddr(ip_hdr
->ih_src
); printf("\n"));
502 static void icmp_echo_request(icmp_port
, ip_data
, ip_len
, ip_hdr
,
503 icmp_data
, icmp_len
, icmp_hdr
)
504 icmp_port_t
*icmp_port
;
505 acc_t
*ip_data
, *icmp_data
;
506 int ip_len
, icmp_len
;
508 icmp_hdr_t
*icmp_hdr
;
510 acc_t
*repl_ip_hdr
, *repl_icmp
;
511 ipaddr_t tmpaddr
, locaddr
, netmask
;
512 icmp_hdr_t
*repl_icmp_hdr
;
516 if (icmp_hdr
->ih_code
!= 0)
519 printf("got an icmp echo request with unknown code (%d)\n",
525 if (icmp_len
< ICMP_MIN_HDR_SIZE
+ sizeof(icmp_id_seq_t
))
527 DBLOCK(1, printf("got an incomplete icmp echo request\n"));
532 tmpaddr
= ntohl(ip_hdr
->ih_dst
);
533 if ((tmpaddr
& 0xe0000000) == 0xe0000000 &&
534 tmpaddr
!= 0xffffffff)
536 /* Respond only to the all hosts multicast address until
537 * a decent listening service has been implemented
539 if (tmpaddr
!= 0xe0000001)
547 /* Limit subnet broadcasts to the local net */
548 ip_port
= &ip_port_table
[icmp_port
->icp_ipport
];
549 locaddr
= ip_port
->ip_ipaddr
;
550 netmask
= ip_port
->ip_subnetmask
;
551 if (ip_hdr
->ih_dst
== (locaddr
| ~netmask
) &&
552 (ip_port
->ip_flags
& IPF_SUBNET_BCAST
) &&
553 ((ip_hdr
->ih_src
^ locaddr
) & netmask
) != 0)
555 /* Directed broadcast */
561 repl_ip_hdr
= make_repl_ip(ip_hdr
, ip_len
);
562 repl_icmp
= bf_memreq (ICMP_MIN_HDR_SIZE
);
563 repl_icmp_hdr
= (icmp_hdr_t
*)ptr2acc_data(repl_icmp
);
564 repl_icmp_hdr
->ih_type
= ICMP_TYPE_ECHO_REPL
;
565 repl_icmp_hdr
->ih_code
= 0;
568 printf("ih_chksum= 0x%x, ih_type= 0x%x, repl->ih_type= 0x%x\n",
569 icmp_hdr
->ih_chksum
, *(u16_t
*)&icmp_hdr
->ih_type
,
570 *(u16_t
*)&repl_icmp_hdr
->ih_type
));
571 tmp_chksum
= (~icmp_hdr
->ih_chksum
& 0xffff) -
572 (i32_t
)*(u16_t
*)&icmp_hdr
->ih_type
+
573 *(u16_t
*)&repl_icmp_hdr
->ih_type
;
574 tmp_chksum
= (tmp_chksum
>> 16) + (tmp_chksum
& 0xffff);
575 tmp_chksum
= (tmp_chksum
>> 16) + (tmp_chksum
& 0xffff);
576 repl_icmp_hdr
->ih_chksum
= ~tmp_chksum
;
577 DBLOCK(2, printf("sending chksum 0x%x\n", repl_icmp_hdr
->ih_chksum
));
579 repl_ip_hdr
->acc_next
= repl_icmp
;
580 repl_icmp
->acc_next
= bf_cut (icmp_data
, ICMP_MIN_HDR_SIZE
,
581 icmp_len
- ICMP_MIN_HDR_SIZE
);
586 enqueue_pack(icmp_port
, repl_ip_hdr
);
589 static u16_t
icmp_pack_oneCsum(icmp_pack
)
601 for (; icmp_pack
; icmp_pack
= icmp_pack
->acc_next
)
603 data_ptr
= ptr2acc_data(icmp_pack
);
604 length
= icmp_pack
->acc_length
;
610 byte_buf
[1]= *data_ptr
;
611 prev
= oneC_sum(prev
, (u16_t
*)byte_buf
, 2);
620 byte_buf
[0]= data_ptr
[length
];
624 prev
= oneC_sum (prev
, (u16_t
*)data_ptr
, length
);
627 prev
= oneC_sum (prev
, (u16_t
*)byte_buf
, 1);
631 static acc_t
*make_repl_ip(ip_hdr
, ip_len
)
635 ip_hdr_t
*repl_ip_hdr
;
639 if (ip_len
>IP_MIN_HDR_SIZE
)
641 DBLOCK(1, printf("ip_hdr options NOT supported (yet?)\n"));
642 ip_len
= IP_MIN_HDR_SIZE
;
645 repl_hdr_len
= IP_MIN_HDR_SIZE
;
647 repl
= bf_memreq(repl_hdr_len
);
649 repl_ip_hdr
= (ip_hdr_t
*)ptr2acc_data(repl
);
651 repl_ip_hdr
->ih_vers_ihl
= repl_hdr_len
>> 2;
652 repl_ip_hdr
->ih_tos
= ip_hdr
->ih_tos
;
653 repl_ip_hdr
->ih_ttl
= ICMP_DEF_TTL
;
654 repl_ip_hdr
->ih_proto
= IPPROTO_ICMP
;
655 repl_ip_hdr
->ih_dst
= ip_hdr
->ih_src
;
656 repl_ip_hdr
->ih_flags_fragoff
= 0;
661 static void enqueue_pack(icmp_port
, reply_ip_hdr
)
662 icmp_port_t
*icmp_port
;
669 if (icmp_port
->icp_rate_count
>= ICMP_MAX_RATE
)
671 /* Something is going wrong; check policy */
672 r
= icmp_rate_limit(icmp_port
, reply_ip_hdr
);
675 bf_afree(reply_ip_hdr
);
681 icmp_port
->icp_rate_count
++;
683 reply_ip_hdr
->acc_ext_link
= 0;
685 if (icmp_port
->icp_head_queue
)
687 icmp_port
->icp_tail_queue
->acc_ext_link
=
692 icmp_port
->icp_head_queue
= reply_ip_hdr
;
694 reply_ip_hdr
->acc_ext_link
= NULL
;
695 icmp_port
->icp_tail_queue
= reply_ip_hdr
;
697 if (!(icmp_port
->icp_flags
& ICPF_WRITE_IP
))
699 icmp_port
->icp_flags
|= ICPF_WRITE_IP
;
700 ev_arg
.ev_ptr
= icmp_port
;
701 ev_enqueue(&icmp_port
->icp_event
, icmp_write
, ev_arg
);
705 static int icmp_rate_limit(icmp_port
, reply_ip_hdr
)
706 icmp_port_t
*icmp_port
;
712 icmp_hdr_t
*icmp_hdr
;
713 int hdrlen
, icmp_hdr_len
, type
;
715 /* Check the time first */
717 if (t
>= icmp_port
->icp_rate_lasttime
+ ICMP_RATE_INTERVAL
)
719 icmp_port
->icp_rate_lasttime
= t
;
720 icmp_port
->icp_rate_count
= 0;
724 icmp_port
->icp_rate_count
++;
726 /* Adjust report limit if necessary */
727 if (icmp_port
->icp_rate_count
>
728 icmp_port
->icp_rate_report
+ICMP_RATE_WARN
)
730 icmp_port
->icp_rate_report
*= 2;
734 /* Do we need to report */
735 if (icmp_port
->icp_rate_count
< icmp_port
->icp_rate_report
)
738 pack
= bf_dupacc(reply_ip_hdr
);
739 pack
= bf_packIffLess(pack
, IP_MIN_HDR_SIZE
);
740 ip_hdr
= (ip_hdr_t
*)ptr2acc_data(pack
);
741 printf("icmp[%d]: dropping ICMP packet #%d to ",
742 icmp_port
->icp_ipport
, icmp_port
->icp_rate_count
);
743 writeIpAddr(ip_hdr
->ih_dst
);
744 hdrlen
= (ip_hdr
->ih_vers_ihl
& IH_IHL_MASK
)*4;
745 pack
= bf_packIffLess(pack
, hdrlen
+ICMP_MIN_HDR_SIZE
);
746 ip_hdr
= (ip_hdr_t
*)ptr2acc_data(pack
);
747 icmp_hdr
= (icmp_hdr_t
*)(ptr2acc_data(pack
)+hdrlen
);
748 type
= icmp_hdr
->ih_type
;
749 printf(" type %d, code %d\n", type
, icmp_hdr
->ih_code
);
752 case ICMP_TYPE_DST_UNRCH
:
753 case ICMP_TYPE_SRC_QUENCH
:
754 case ICMP_TYPE_REDIRECT
:
755 case ICMP_TYPE_TIME_EXCEEDED
:
756 case ICMP_TYPE_PARAM_PROBLEM
:
757 icmp_hdr_len
= offsetof(struct icmp_hdr
, ih_dun
);
758 pack
= bf_packIffLess(pack
,
759 hdrlen
+icmp_hdr_len
+IP_MIN_HDR_SIZE
);
760 ip_hdr
= (ip_hdr_t
*)(ptr2acc_data(pack
)+hdrlen
+icmp_hdr_len
);
761 icmp_hdr
= (icmp_hdr_t
*)(ptr2acc_data(pack
)+hdrlen
);
762 printf("\tinfo %08x, original dst ",
763 ntohs(icmp_hdr
->ih_hun
.ihh_unused
));
764 writeIpAddr(ip_hdr
->ih_dst
);
765 printf(", proto %d, length %u\n",
766 ip_hdr
->ih_proto
, ntohs(ip_hdr
->ih_length
));
771 bf_afree(pack
); pack
= NULL
;
776 static void icmp_write(ev
, ev_arg
)
781 icmp_port_t
*icmp_port
;
784 icmp_port
= ev_arg
.ev_ptr
;
785 assert(ev
== &icmp_port
->icp_event
);
787 assert (icmp_port
->icp_flags
& ICPF_WRITE_IP
);
788 assert (!(icmp_port
->icp_flags
& ICPF_WRITE_SP
));
790 while (icmp_port
->icp_head_queue
!= NULL
)
792 data
= icmp_port
->icp_head_queue
;
793 icmp_port
->icp_head_queue
= data
->acc_ext_link
;
795 result
= ip_send(icmp_port
->icp_ipfd
, data
,
797 if (result
!= NW_WOULDBLOCK
)
801 DBLOCK(1, printf("icmp_write: error %d\n", result
););
805 assert(icmp_port
->icp_write_pack
== NULL
);
806 icmp_port
->icp_write_pack
= data
;
808 result
= ip_write(icmp_port
->icp_ipfd
,
809 bf_bufsize(icmp_port
->icp_write_pack
));
810 if (result
== NW_SUSPEND
)
812 icmp_port
->icp_flags
|= ICPF_WRITE_SP
;
816 icmp_port
->icp_flags
&= ~ICPF_WRITE_IP
;
819 static void icmp_buffree(priority
)
824 icmp_port_t
*icmp_port
;
826 if (priority
== ICMP_PRI_QUEUE
)
828 for (i
=0, icmp_port
= icmp_port_table
; i
<ip_conf_nr
;
831 while(icmp_port
->icp_head_queue
)
833 tmp_acc
= icmp_port
->icp_head_queue
;
834 icmp_port
->icp_head_queue
=
835 tmp_acc
->acc_ext_link
;
842 #ifdef BUF_CONSISTENCY_CHECK
843 static void icmp_bufcheck()
846 icmp_port_t
*icmp_port
;
849 for (i
= 0, icmp_port
= icmp_port_table
; i
<ip_conf_nr
; i
++, icmp_port
++)
851 for (pack
= icmp_port
->icp_head_queue
; pack
;
852 pack
= pack
->acc_ext_link
)
856 bf_check_acc(icmp_port
->icp_write_pack
);
861 static void icmp_dst_unreach(icmp_port
, ip_pack
, ip_hdr_len
, ip_hdr
, icmp_pack
,
863 icmp_port_t
*icmp_port
;
869 icmp_hdr_t
*icmp_hdr
;
872 ip_hdr_t
*old_ip_hdr
;
875 size_t old_pack_size
;
878 if (icmp_len
< 8 + IP_MIN_HDR_SIZE
)
880 DBLOCK(1, printf("dest unrch with wrong size\n"));
883 old_ip_pack
= bf_cut (icmp_pack
, 8, icmp_len
-8);
884 old_ip_pack
= bf_packIffLess(old_ip_pack
, IP_MIN_HDR_SIZE
);
885 old_ip_hdr
= (ip_hdr_t
*)ptr2acc_data(old_ip_pack
);
887 if (old_ip_hdr
->ih_src
!= ip_hdr
->ih_dst
)
889 DBLOCK(1, printf("dest unrch based on wrong packet\n"));
890 bf_afree(old_ip_pack
);
894 ip_port_nr
= icmp_port
->icp_ipport
;
896 switch(icmp_hdr
->ih_code
)
899 dst
= old_ip_hdr
->ih_dst
;
900 mask
= ip_get_netmask(dst
);
901 ipr_destunrch (ip_port_nr
, dst
& mask
, mask
,
904 case ICMP_HOST_UNRCH
:
905 ipr_destunrch (ip_port_nr
, old_ip_hdr
->ih_dst
, (ipaddr_t
)-1,
908 case ICMP_PORT_UNRCH
:
909 /* At the moment we don't do anything with this information.
910 * It should be handed to the appropriate transport layer.
913 case ICMP_FRAGM_AND_DF
:
915 DBLOCK(1, printf("icmp_dst_unreach: got mtu icmp from ");
916 writeIpAddr(ip_hdr
->ih_src
);
917 printf("; original destination: ");
918 writeIpAddr(old_ip_hdr
->ih_dst
);
919 printf("; protocol: %d\n",
920 old_ip_hdr
->ih_proto
));
921 old_pack_size
= ntohs(old_ip_hdr
->ih_length
);
924 new_mtu
= ntohs(icmp_hdr
->ih_hun
.ihh_mtu
.im_mtu
);
925 if (!new_mtu
|| new_mtu
> old_pack_size
)
926 new_mtu
= old_pack_size
-1;
927 ipr_mtu(ip_port_nr
, old_ip_hdr
->ih_dst
, new_mtu
,
932 DBLOCK(1, printf("icmp_dst_unreach: got strange code %d from ",
934 writeIpAddr(ip_hdr
->ih_src
);
935 printf("; original destination: ");
936 writeIpAddr(old_ip_hdr
->ih_dst
);
937 printf("; protocol: %d\n",
938 old_ip_hdr
->ih_proto
));
941 bf_afree(old_ip_pack
);
944 static void icmp_time_exceeded(icmp_port
, ip_pack
, ip_hdr_len
, ip_hdr
,
945 icmp_pack
, icmp_len
, icmp_hdr
)
946 icmp_port_t
*icmp_port
;
952 icmp_hdr_t
*icmp_hdr
;
955 ip_hdr_t
*old_ip_hdr
;
958 if (icmp_len
< 8 + IP_MIN_HDR_SIZE
)
960 DBLOCK(1, printf("time exceeded with wrong size\n"));
963 old_ip_pack
= bf_cut (icmp_pack
, 8, icmp_len
-8);
964 old_ip_pack
= bf_packIffLess(old_ip_pack
, IP_MIN_HDR_SIZE
);
965 old_ip_hdr
= (ip_hdr_t
*)ptr2acc_data(old_ip_pack
);
967 if (old_ip_hdr
->ih_src
!= ip_hdr
->ih_dst
)
969 DBLOCK(1, printf("time exceeded based on wrong packet\n"));
970 bf_afree(old_ip_pack
);
974 ip_port_nr
= icmp_port
->icp_ipport
;
976 switch(icmp_hdr
->ih_code
)
979 ipr_ttl_exc (ip_port_nr
, old_ip_hdr
->ih_dst
, (ipaddr_t
)-1,
982 case ICMP_FRAG_REASSEM
:
983 /* Ignore reassembly time-outs. */
986 DBLOCK(1, printf("got strange code: %d\n",
990 bf_afree(old_ip_pack
);
993 static void icmp_router_advertisement(icmp_port
, icmp_pack
, icmp_len
, icmp_hdr
)
994 icmp_port_t
*icmp_port
;
997 icmp_hdr_t
*icmp_hdr
;
1008 printf("router advertisement with wrong size (%d)\n",
1012 if (icmp_hdr
->ih_code
!= 0)
1015 printf("router advertisement with wrong code (%d)\n",
1016 icmp_hdr
->ih_code
));
1019 entries
= icmp_hdr
->ih_hun
.ihh_ram
.iram_na
;
1020 entry_size
= icmp_hdr
->ih_hun
.ihh_ram
.iram_aes
* 4;
1024 "router advertisement with wrong number of entries (%d)\n",
1031 "router advertisement with wrong entry size (%d)\n",
1035 if (icmp_len
< 8 + entries
* entry_size
)
1038 printf("router advertisement with wrong size\n");
1040 "\t(entries= %d, entry_size= %d, icmp_len= %d)\n",
1041 entries
, entry_size
, icmp_len
));
1044 lifetime
= ntohs(icmp_hdr
->ih_hun
.ihh_ram
.iram_lt
);
1045 if (lifetime
> 9000)
1048 "router advertisement with wrong lifetime (%d)\n",
1052 for (i
= 0, bufp
= (char *)&icmp_hdr
->ih_dun
.uhd_data
[0]; i
< entries
; i
++,
1058 addr
= *(ipaddr_t
*)bufp
;
1059 pref
= ntohl(*(u32_t
*)(bufp
+4));
1060 ipr_add_oroute(icmp_port
->icp_ipport
, HTONL(0L), HTONL(0L),
1061 addr
, lifetime
? lifetime
* HZ
: 1,
1062 1, 0, 0, pref
, NULL
);
1066 static void icmp_redirect(icmp_port
, ip_hdr
, icmp_pack
, icmp_len
, icmp_hdr
)
1067 icmp_port_t
*icmp_port
;
1071 icmp_hdr_t
*icmp_hdr
;
1074 ip_hdr_t
*old_ip_hdr
;
1078 if (icmp_len
< 8 + IP_MIN_HDR_SIZE
)
1080 DBLOCK(1, printf("redirect with wrong size\n"));
1083 old_ip_pack
= bf_cut (icmp_pack
, 8, icmp_len
-8);
1084 old_ip_pack
= bf_packIffLess(old_ip_pack
, IP_MIN_HDR_SIZE
);
1085 old_ip_hdr
= (ip_hdr_t
*)ptr2acc_data(old_ip_pack
);
1087 ip_port_nr
= icmp_port
->icp_ipport
;
1089 switch(icmp_hdr
->ih_code
)
1091 case ICMP_REDIRECT_NET
:
1092 dst
= old_ip_hdr
->ih_dst
;
1093 mask
= ip_get_netmask(dst
);
1094 ipr_redirect (ip_port_nr
, dst
& mask
, mask
,
1095 ip_hdr
->ih_src
, icmp_hdr
->ih_hun
.ihh_gateway
,
1096 IPR_REDIRECT_TIMEOUT
);
1098 case ICMP_REDIRECT_HOST
:
1099 ipr_redirect (ip_port_nr
, old_ip_hdr
->ih_dst
, (ipaddr_t
)-1,
1100 ip_hdr
->ih_src
, icmp_hdr
->ih_hun
.ihh_gateway
,
1101 IPR_REDIRECT_TIMEOUT
);
1104 DBLOCK(1, printf("got strange code: %d\n",
1105 icmp_hdr
->ih_code
));
1108 bf_afree(old_ip_pack
);
1111 static acc_t
*icmp_err_pack(pack
, icmp_hdr_pp
)
1113 icmp_hdr_t
**icmp_hdr_pp
;
1116 icmp_hdr_t
*icmp_hdr_p
;
1117 acc_t
*ip_pack
, *icmp_pack
, *tmp_pack
;
1118 int ip_hdr_len
, icmp_hdr_len
, ih_type
;
1119 size_t size
, pack_len
;
1123 pack
= bf_packIffLess(pack
, IP_MIN_HDR_SIZE
);
1124 ip_hdr
= (ip_hdr_t
*)ptr2acc_data(pack
);
1125 ip_hdr_len
= (ip_hdr
->ih_vers_ihl
& IH_IHL_MASK
) << 2;
1126 pack_len
= bf_bufsize(pack
);
1128 /* If the IP protocol is ICMP (except echo request/reply) or the
1129 * fragment offset is non-zero,
1130 * drop the packet. Also check if the source address is valid.
1132 if ((ntohs(ip_hdr
->ih_flags_fragoff
) & IH_FRAGOFF_MASK
) != 0)
1137 if (ip_hdr
->ih_proto
== IPPROTO_ICMP
)
1139 if (ip_hdr_len
>IP_MIN_HDR_SIZE
)
1141 pack
= bf_packIffLess(pack
, ip_hdr_len
);
1142 ip_hdr
= (ip_hdr_t
*)ptr2acc_data(pack
);
1145 if (pack_len
< ip_hdr_len
+ICMP_MIN_HDR_SIZE
)
1150 icmp_pack
= bf_cut(pack
, ip_hdr_len
, ICMP_MIN_HDR_SIZE
);
1151 icmp_pack
= bf_packIffLess (icmp_pack
, ICMP_MIN_HDR_SIZE
);
1152 icmp_hdr_p
= (icmp_hdr_t
*)ptr2acc_data(icmp_pack
);
1153 ih_type
= icmp_hdr_p
->ih_type
;
1154 bf_afree(icmp_pack
); icmp_pack
= NULL
;
1156 if (ih_type
!= ICMP_TYPE_ECHO_REQ
&&
1157 ih_type
!= ICMP_TYPE_ECHO_REPL
)
1163 dest
= ip_hdr
->ih_src
;
1164 nettype
= ip_nettype(dest
);
1165 if (nettype
!= IPNT_CLASS_A
&& nettype
!= IPNT_LOCAL
&&
1166 nettype
!= IPNT_CLASS_B
&& nettype
!= IPNT_CLASS_C
)
1168 printf("icmp_err_pack: invalid source address: ");
1175 /* Take the IP header and the first 64 bits of user data. */
1176 size
= ntohs(ip_hdr
->ih_length
);
1177 if (size
< ip_hdr_len
|| pack_len
< size
)
1179 printf("icmp_err_pack: wrong packet size:\n");
1180 printf("\thdrlen= %d, ih_length= %d, bufsize= %d\n",
1181 ip_hdr_len
, size
, pack_len
);
1185 if (ip_hdr_len
+ 8 < size
)
1187 tmp_pack
= bf_cut(pack
, 0, size
);
1192 /* Create a minimal size ICMP hdr. */
1193 icmp_hdr_len
= offsetof(icmp_hdr_t
, ih_dun
);
1194 icmp_pack
= bf_memreq(icmp_hdr_len
);
1195 pack
= bf_append(icmp_pack
, pack
);
1196 size
+= icmp_hdr_len
;
1197 pack
= bf_packIffLess(pack
, icmp_hdr_len
);
1198 icmp_hdr_p
= (icmp_hdr_t
*)ptr2acc_data(pack
);
1199 icmp_hdr_p
->ih_type
= 0;
1200 icmp_hdr_p
->ih_code
= 0;
1201 icmp_hdr_p
->ih_chksum
= 0;
1202 icmp_hdr_p
->ih_hun
.ihh_unused
= 0;
1203 icmp_hdr_p
->ih_chksum
= ~icmp_pack_oneCsum(pack
);
1204 *icmp_hdr_pp
= icmp_hdr_p
;
1206 /* Create an IP header */
1207 ip_hdr_len
= IP_MIN_HDR_SIZE
;
1209 ip_pack
= bf_memreq(ip_hdr_len
);
1210 ip_hdr
= (ip_hdr_t
*)ptr2acc_data(ip_pack
);
1212 ip_hdr
->ih_vers_ihl
= ip_hdr_len
>> 2;
1214 ip_hdr
->ih_length
= htons(ip_hdr_len
+ size
);
1215 ip_hdr
->ih_flags_fragoff
= 0;
1216 ip_hdr
->ih_ttl
= ICMP_DEF_TTL
;
1217 ip_hdr
->ih_proto
= IPPROTO_ICMP
;
1218 ip_hdr
->ih_dst
= dest
;
1220 assert(ip_pack
->acc_next
== NULL
);
1221 ip_pack
->acc_next
= pack
;
1226 * $PchId: icmp.c,v 1.23 2005/06/28 14:16:56 philip Exp $