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 PRIVATE icmp_port_t
*icmp_port_table
;
52 FORWARD
void icmp_main
ARGS(( icmp_port_t
*icmp_port
));
53 FORWARD acc_t
*icmp_getdata
ARGS(( int port
, size_t offset
,
54 size_t count
, int for_ioctl
));
55 FORWARD
int icmp_putdata
ARGS(( int port
, size_t offset
,
56 acc_t
*data
, int for_ioctl
));
57 FORWARD
void icmp_read
ARGS(( icmp_port_t
*icmp_port
));
58 FORWARD
void process_data
ARGS(( icmp_port_t
*icmp_port
,
60 FORWARD u16_t icmp_pack_oneCsum
ARGS(( acc_t
*ip_pack
));
61 FORWARD
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 FORWARD
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 FORWARD
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 FORWARD
void icmp_router_advertisement
ARGS(( icmp_port_t
*icmp_port
,
71 acc_t
*icmp_pack
, int icmp_len
, icmp_hdr_t
*icmp_hdr
));
72 FORWARD
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 FORWARD acc_t
*make_repl_ip
ARGS(( ip_hdr_t
*ip_hdr
,
77 FORWARD
void enqueue_pack
ARGS(( icmp_port_t
*icmp_port
,
78 acc_t
*reply_ip_hdr
));
79 FORWARD
int icmp_rate_limit
ARGS(( icmp_port_t
*icmp_port
,
80 acc_t
*reply_ip_hdr
));
81 FORWARD
void icmp_write
ARGS(( event_t
*ev
, ev_arg_t ev_arg
));
82 FORWARD
void icmp_buffree
ARGS(( int priority
));
83 FORWARD acc_t
*icmp_err_pack
ARGS(( acc_t
*pack
, icmp_hdr_t
**icmp_hdr_pp
));
84 #ifdef BUF_CONSISTENCY_CHECK
85 FORWARD
void icmp_bufcheck
ARGS(( void ));
88 PUBLIC
void icmp_prep()
90 icmp_port_table
= alloc(ip_conf_nr
* sizeof(icmp_port_table
[0]));
93 PUBLIC
void icmp_init()
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 PRIVATE
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 PRIVATE 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 PRIVATE
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 PRIVATE
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 PUBLIC
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 PUBLIC
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 PUBLIC
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
);
374 PUBLIC
void icmp_snd_mtu(port_nr
, pack
, mtu
)
379 icmp_hdr_t
*icmp_hdr
;
380 icmp_port_t
*icmp_port
;
382 if (port_nr
>= 0 && port_nr
< ip_conf_nr
)
383 icmp_port
= &icmp_port_table
[port_nr
];
386 printf("icmp_snd_mtu: strange port %d\n", port_nr
);
391 pack
= icmp_err_pack(pack
, &icmp_hdr
);
394 icmp_hdr
->ih_type
= ICMP_TYPE_DST_UNRCH
;
395 icmp_hdr
->ih_code
= ICMP_FRAGM_AND_DF
;
396 icmp_hdr
->ih_hun
.ihh_mtu
.im_mtu
= htons(mtu
);
397 icmp_hdr
->ih_chksum
= ~oneC_sum(~icmp_hdr
->ih_chksum
,
398 (u16_t
*)&icmp_hdr
->ih_type
, 2);
399 icmp_hdr
->ih_chksum
= ~oneC_sum(~icmp_hdr
->ih_chksum
,
400 (u16_t
*)&icmp_hdr
->ih_hun
.ihh_mtu
.im_mtu
, 2);
401 enqueue_pack(icmp_port
, pack
);
404 PRIVATE
void process_data(icmp_port
, data
)
405 icmp_port_t
*icmp_port
;
409 icmp_hdr_t
*icmp_hdr
;
414 /* Align entire packet */
415 data
= bf_align(data
, BUF_S
, 4);
417 data
= bf_packIffLess(data
, IP_MIN_HDR_SIZE
);
418 ip_hdr
= (ip_hdr_t
*)ptr2acc_data(data
);
419 DIFBLOCK(0x10, (ip_hdr
->ih_dst
& HTONL(0xf0000000)) == HTONL(0xe0000000),
420 printf("got multicast packet\n"));
421 ip_hdr_len
= (ip_hdr
->ih_vers_ihl
& IH_IHL_MASK
) << 2;
423 if (ip_hdr_len
>IP_MIN_HDR_SIZE
)
425 data
= bf_packIffLess(data
, ip_hdr_len
);
426 ip_hdr
= (ip_hdr_t
*)ptr2acc_data(data
);
429 pack_len
= bf_bufsize(data
);
430 pack_len
-= ip_hdr_len
;
431 if (pack_len
< ICMP_MIN_HDR_SIZE
)
433 if (pack_len
== 0 && ip_hdr
->ih_proto
== 0)
435 /* IP layer reports new ip address, which can be
440 DBLOCK(1, printf("got an incomplete icmp packet\n"));
445 icmp_data
= bf_cut(data
, ip_hdr_len
, pack_len
);
447 icmp_data
= bf_packIffLess (icmp_data
, ICMP_MIN_HDR_SIZE
);
448 icmp_hdr
= (icmp_hdr_t
*)ptr2acc_data(icmp_data
);
450 if ((u16_t
)~icmp_pack_oneCsum(icmp_data
))
453 "got packet with bad checksum (= 0x%x, 0x%x)\n",
455 (u16_t
)~icmp_pack_oneCsum(icmp_data
)));
461 switch (icmp_hdr
->ih_type
)
463 case ICMP_TYPE_ECHO_REPL
:
465 case ICMP_TYPE_DST_UNRCH
:
466 icmp_dst_unreach (icmp_port
, data
, ip_hdr_len
, ip_hdr
,
467 icmp_data
, pack_len
, icmp_hdr
);
469 case ICMP_TYPE_SRC_QUENCH
:
470 /* Ignore src quench ICMPs */
471 DBLOCK(2, printf("ignoring SRC QUENCH ICMP.\n"));
473 case ICMP_TYPE_REDIRECT
:
474 icmp_redirect (icmp_port
, ip_hdr
, icmp_data
, pack_len
,
477 case ICMP_TYPE_ECHO_REQ
:
478 icmp_echo_request(icmp_port
, data
, ip_hdr_len
, ip_hdr
,
479 icmp_data
, pack_len
, icmp_hdr
);
481 case ICMP_TYPE_ROUTER_ADVER
:
482 icmp_router_advertisement(icmp_port
, icmp_data
, pack_len
,
485 case ICMP_TYPE_ROUTE_SOL
:
486 break; /* Should be handled by a routing deamon. */
487 case ICMP_TYPE_TIME_EXCEEDED
:
488 icmp_time_exceeded (icmp_port
, data
, ip_hdr_len
, ip_hdr
,
489 icmp_data
, pack_len
, icmp_hdr
);
492 DBLOCK(1, printf("got an unknown icmp (%d) from ",
494 writeIpAddr(ip_hdr
->ih_src
); printf("\n"));
501 PRIVATE
void icmp_echo_request(icmp_port
, ip_data
, ip_len
, ip_hdr
,
502 icmp_data
, icmp_len
, icmp_hdr
)
503 icmp_port_t
*icmp_port
;
504 acc_t
*ip_data
, *icmp_data
;
505 int ip_len
, icmp_len
;
507 icmp_hdr_t
*icmp_hdr
;
509 acc_t
*repl_ip_hdr
, *repl_icmp
;
510 ipaddr_t tmpaddr
, locaddr
, netmask
;
511 icmp_hdr_t
*repl_icmp_hdr
;
515 if (icmp_hdr
->ih_code
!= 0)
518 printf("got an icmp echo request with unknown code (%d)\n",
524 if (icmp_len
< ICMP_MIN_HDR_SIZE
+ sizeof(icmp_id_seq_t
))
526 DBLOCK(1, printf("got an incomplete icmp echo request\n"));
531 tmpaddr
= ntohl(ip_hdr
->ih_dst
);
532 if ((tmpaddr
& 0xe0000000) == 0xe0000000 &&
533 tmpaddr
!= 0xffffffff)
535 /* Respond only to the all hosts multicast address until
536 * a decent listening service has been implemented
538 if (tmpaddr
!= 0xe0000001)
546 /* Limit subnet broadcasts to the local net */
547 ip_port
= &ip_port_table
[icmp_port
->icp_ipport
];
548 locaddr
= ip_port
->ip_ipaddr
;
549 netmask
= ip_port
->ip_subnetmask
;
550 if (ip_hdr
->ih_dst
== (locaddr
| ~netmask
) &&
551 (ip_port
->ip_flags
& IPF_SUBNET_BCAST
) &&
552 ((ip_hdr
->ih_src
^ locaddr
) & netmask
) != 0)
554 /* Directed broadcast */
560 repl_ip_hdr
= make_repl_ip(ip_hdr
, ip_len
);
561 repl_icmp
= bf_memreq (ICMP_MIN_HDR_SIZE
);
562 repl_icmp_hdr
= (icmp_hdr_t
*)ptr2acc_data(repl_icmp
);
563 repl_icmp_hdr
->ih_type
= ICMP_TYPE_ECHO_REPL
;
564 repl_icmp_hdr
->ih_code
= 0;
567 printf("ih_chksum= 0x%x, ih_type= 0x%x, repl->ih_type= 0x%x\n",
568 icmp_hdr
->ih_chksum
, *(u16_t
*)&icmp_hdr
->ih_type
,
569 *(u16_t
*)&repl_icmp_hdr
->ih_type
));
570 tmp_chksum
= (~icmp_hdr
->ih_chksum
& 0xffff) -
571 (i32_t
)*(u16_t
*)&icmp_hdr
->ih_type
+
572 *(u16_t
*)&repl_icmp_hdr
->ih_type
;
573 tmp_chksum
= (tmp_chksum
>> 16) + (tmp_chksum
& 0xffff);
574 tmp_chksum
= (tmp_chksum
>> 16) + (tmp_chksum
& 0xffff);
575 repl_icmp_hdr
->ih_chksum
= ~tmp_chksum
;
576 DBLOCK(2, printf("sending chksum 0x%x\n", repl_icmp_hdr
->ih_chksum
));
578 repl_ip_hdr
->acc_next
= repl_icmp
;
579 repl_icmp
->acc_next
= bf_cut (icmp_data
, ICMP_MIN_HDR_SIZE
,
580 icmp_len
- ICMP_MIN_HDR_SIZE
);
585 enqueue_pack(icmp_port
, repl_ip_hdr
);
588 PRIVATE u16_t
icmp_pack_oneCsum(icmp_pack
)
600 for (; icmp_pack
; icmp_pack
= icmp_pack
->acc_next
)
602 data_ptr
= ptr2acc_data(icmp_pack
);
603 length
= icmp_pack
->acc_length
;
609 byte_buf
[1]= *data_ptr
;
610 prev
= oneC_sum(prev
, (u16_t
*)byte_buf
, 2);
619 byte_buf
[0]= data_ptr
[length
];
623 prev
= oneC_sum (prev
, (u16_t
*)data_ptr
, length
);
626 prev
= oneC_sum (prev
, (u16_t
*)byte_buf
, 1);
630 PRIVATE acc_t
*make_repl_ip(ip_hdr
, ip_len
)
634 ip_hdr_t
*repl_ip_hdr
;
638 if (ip_len
>IP_MIN_HDR_SIZE
)
640 DBLOCK(1, printf("ip_hdr options NOT supported (yet?)\n"));
641 ip_len
= IP_MIN_HDR_SIZE
;
644 repl_hdr_len
= IP_MIN_HDR_SIZE
;
646 repl
= bf_memreq(repl_hdr_len
);
648 repl_ip_hdr
= (ip_hdr_t
*)ptr2acc_data(repl
);
650 repl_ip_hdr
->ih_vers_ihl
= repl_hdr_len
>> 2;
651 repl_ip_hdr
->ih_tos
= ip_hdr
->ih_tos
;
652 repl_ip_hdr
->ih_ttl
= ICMP_DEF_TTL
;
653 repl_ip_hdr
->ih_proto
= IPPROTO_ICMP
;
654 repl_ip_hdr
->ih_dst
= ip_hdr
->ih_src
;
655 repl_ip_hdr
->ih_flags_fragoff
= 0;
660 PRIVATE
void enqueue_pack(icmp_port
, reply_ip_hdr
)
661 icmp_port_t
*icmp_port
;
668 if (icmp_port
->icp_rate_count
>= ICMP_MAX_RATE
)
670 /* Something is going wrong; check policy */
671 r
= icmp_rate_limit(icmp_port
, reply_ip_hdr
);
674 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 PRIVATE
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 PRIVATE
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 PRIVATE
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 PRIVATE
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 PRIVATE
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 PRIVATE
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 PRIVATE
void icmp_router_advertisement(icmp_port
, icmp_pack
, icmp_len
, icmp_hdr
)
994 icmp_port_t
*icmp_port
;
997 icmp_hdr_t
*icmp_hdr
;
1011 printf("router advertisement with wrong size (%d)\n",
1015 if (icmp_hdr
->ih_code
!= 0)
1018 printf("router advertisement with wrong code (%d)\n",
1019 icmp_hdr
->ih_code
));
1022 entries
= icmp_hdr
->ih_hun
.ihh_ram
.iram_na
;
1023 entry_size
= icmp_hdr
->ih_hun
.ihh_ram
.iram_aes
* 4;
1027 "router advertisement with wrong number of entries (%d)\n",
1034 "router advertisement with wrong entry size (%d)\n",
1038 if (icmp_len
< 8 + entries
* entry_size
)
1041 printf("router advertisement with wrong size\n");
1043 "\t(entries= %d, entry_size= %d, icmp_len= %d)\n",
1044 entries
, entry_size
, icmp_len
));
1047 lifetime
= ntohs(icmp_hdr
->ih_hun
.ihh_ram
.iram_lt
);
1048 if (lifetime
> 9000)
1051 "router advertisement with wrong lifetime (%d)\n",
1055 ip_port
= &ip_port_table
[icmp_port
->icp_ipport
];
1056 for (i
= 0, bufp
= (char *)&icmp_hdr
->ih_dun
.uhd_data
[0]; i
< entries
; i
++,
1059 addr
= *(ipaddr_t
*)bufp
;
1060 pref
= ntohl(*(u32_t
*)(bufp
+4));
1061 ipr_add_oroute(icmp_port
->icp_ipport
, HTONL(0L), HTONL(0L),
1062 addr
, lifetime
? lifetime
* HZ
: 1,
1063 1, 0, 0, pref
, NULL
);
1067 PRIVATE
void icmp_redirect(icmp_port
, ip_hdr
, icmp_pack
, icmp_len
, icmp_hdr
)
1068 icmp_port_t
*icmp_port
;
1072 icmp_hdr_t
*icmp_hdr
;
1075 ip_hdr_t
*old_ip_hdr
;
1079 if (icmp_len
< 8 + IP_MIN_HDR_SIZE
)
1081 DBLOCK(1, printf("redirect with wrong size\n"));
1084 old_ip_pack
= bf_cut (icmp_pack
, 8, icmp_len
-8);
1085 old_ip_pack
= bf_packIffLess(old_ip_pack
, IP_MIN_HDR_SIZE
);
1086 old_ip_hdr
= (ip_hdr_t
*)ptr2acc_data(old_ip_pack
);
1088 ip_port_nr
= icmp_port
->icp_ipport
;
1090 switch(icmp_hdr
->ih_code
)
1092 case ICMP_REDIRECT_NET
:
1093 dst
= old_ip_hdr
->ih_dst
;
1094 mask
= ip_get_netmask(dst
);
1095 ipr_redirect (ip_port_nr
, dst
& mask
, mask
,
1096 ip_hdr
->ih_src
, icmp_hdr
->ih_hun
.ihh_gateway
,
1097 IPR_REDIRECT_TIMEOUT
);
1099 case ICMP_REDIRECT_HOST
:
1100 ipr_redirect (ip_port_nr
, old_ip_hdr
->ih_dst
, (ipaddr_t
)-1,
1101 ip_hdr
->ih_src
, icmp_hdr
->ih_hun
.ihh_gateway
,
1102 IPR_REDIRECT_TIMEOUT
);
1105 DBLOCK(1, printf("got strange code: %d\n",
1106 icmp_hdr
->ih_code
));
1109 bf_afree(old_ip_pack
);
1112 PRIVATE acc_t
*icmp_err_pack(pack
, icmp_hdr_pp
)
1114 icmp_hdr_t
**icmp_hdr_pp
;
1117 icmp_hdr_t
*icmp_hdr_p
;
1118 acc_t
*ip_pack
, *icmp_pack
, *tmp_pack
;
1119 int ip_hdr_len
, icmp_hdr_len
, ih_type
;
1120 size_t size
, pack_len
;
1121 ipaddr_t dest
, netmask
;
1124 pack
= bf_packIffLess(pack
, IP_MIN_HDR_SIZE
);
1125 ip_hdr
= (ip_hdr_t
*)ptr2acc_data(pack
);
1126 ip_hdr_len
= (ip_hdr
->ih_vers_ihl
& IH_IHL_MASK
) << 2;
1127 pack_len
= bf_bufsize(pack
);
1129 /* If the IP protocol is ICMP (except echo request/reply) or the
1130 * fragment offset is non-zero,
1131 * drop the packet. Also check if the source address is valid.
1133 if ((ntohs(ip_hdr
->ih_flags_fragoff
) & IH_FRAGOFF_MASK
) != 0)
1138 if (ip_hdr
->ih_proto
== IPPROTO_ICMP
)
1140 if (ip_hdr_len
>IP_MIN_HDR_SIZE
)
1142 pack
= bf_packIffLess(pack
, ip_hdr_len
);
1143 ip_hdr
= (ip_hdr_t
*)ptr2acc_data(pack
);
1146 if (pack_len
< ip_hdr_len
+ICMP_MIN_HDR_SIZE
)
1151 icmp_pack
= bf_cut(pack
, ip_hdr_len
, ICMP_MIN_HDR_SIZE
);
1152 icmp_pack
= bf_packIffLess (icmp_pack
, ICMP_MIN_HDR_SIZE
);
1153 icmp_hdr_p
= (icmp_hdr_t
*)ptr2acc_data(icmp_pack
);
1154 ih_type
= icmp_hdr_p
->ih_type
;
1155 bf_afree(icmp_pack
); icmp_pack
= NULL
;
1157 if (ih_type
!= ICMP_TYPE_ECHO_REQ
&&
1158 ih_type
!= ICMP_TYPE_ECHO_REPL
)
1164 dest
= ip_hdr
->ih_src
;
1165 nettype
= ip_nettype(dest
);
1166 netmask
= ip_netmask(nettype
);
1167 if (nettype
!= IPNT_CLASS_A
&& nettype
!= IPNT_LOCAL
&&
1168 nettype
!= IPNT_CLASS_B
&& nettype
!= IPNT_CLASS_C
)
1170 printf("icmp_err_pack: invalid source address: ");
1177 /* Take the IP header and the first 64 bits of user data. */
1178 size
= ntohs(ip_hdr
->ih_length
);
1179 if (size
< ip_hdr_len
|| pack_len
< size
)
1181 printf("icmp_err_pack: wrong packet size:\n");
1182 printf("\thdrlen= %d, ih_length= %d, bufsize= %d\n",
1183 ip_hdr_len
, size
, pack_len
);
1187 if (ip_hdr_len
+ 8 < size
)
1189 tmp_pack
= bf_cut(pack
, 0, size
);
1194 /* Create a minimal size ICMP hdr. */
1195 icmp_hdr_len
= offsetof(icmp_hdr_t
, ih_dun
);
1196 icmp_pack
= bf_memreq(icmp_hdr_len
);
1197 pack
= bf_append(icmp_pack
, pack
);
1198 size
+= icmp_hdr_len
;
1199 pack
= bf_packIffLess(pack
, icmp_hdr_len
);
1200 icmp_hdr_p
= (icmp_hdr_t
*)ptr2acc_data(pack
);
1201 icmp_hdr_p
->ih_type
= 0;
1202 icmp_hdr_p
->ih_code
= 0;
1203 icmp_hdr_p
->ih_chksum
= 0;
1204 icmp_hdr_p
->ih_hun
.ihh_unused
= 0;
1205 icmp_hdr_p
->ih_chksum
= ~icmp_pack_oneCsum(pack
);
1206 *icmp_hdr_pp
= icmp_hdr_p
;
1208 /* Create an IP header */
1209 ip_hdr_len
= IP_MIN_HDR_SIZE
;
1211 ip_pack
= bf_memreq(ip_hdr_len
);
1212 ip_hdr
= (ip_hdr_t
*)ptr2acc_data(ip_pack
);
1214 ip_hdr
->ih_vers_ihl
= ip_hdr_len
>> 2;
1216 ip_hdr
->ih_length
= htons(ip_hdr_len
+ size
);
1217 ip_hdr
->ih_flags_fragoff
= 0;
1218 ip_hdr
->ih_ttl
= ICMP_DEF_TTL
;
1219 ip_hdr
->ih_proto
= IPPROTO_ICMP
;
1220 ip_hdr
->ih_dst
= dest
;
1222 assert(ip_pack
->acc_next
== NULL
);
1223 ip_pack
->acc_next
= pack
;
1228 * $PchId: icmp.c,v 1.23 2005/06/28 14:16:56 philip Exp $