[9] | 1 | /*
|
---|
| 2 | icmp.c
|
---|
| 3 |
|
---|
| 4 | Copyright 1995 Philip Homburg
|
---|
| 5 | */
|
---|
| 6 |
|
---|
| 7 | #include "inet.h"
|
---|
| 8 | #include "buf.h"
|
---|
| 9 | #include "event.h"
|
---|
| 10 | #include "type.h"
|
---|
| 11 |
|
---|
| 12 | #include "assert.h"
|
---|
| 13 | #include "clock.h"
|
---|
| 14 | #include "icmp.h"
|
---|
| 15 | #include "icmp_lib.h"
|
---|
| 16 | #include "io.h"
|
---|
| 17 | #include "ip.h"
|
---|
| 18 | #include "ip_int.h"
|
---|
| 19 | #include "ipr.h"
|
---|
| 20 |
|
---|
| 21 | THIS_FILE
|
---|
| 22 |
|
---|
| 23 | typedef struct icmp_port
|
---|
| 24 | {
|
---|
| 25 | int icp_flags;
|
---|
| 26 | int icp_state;
|
---|
| 27 | int icp_ipport;
|
---|
| 28 | int icp_ipfd;
|
---|
| 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;
|
---|
| 35 | event_t icp_event;
|
---|
| 36 | } icmp_port_t;
|
---|
| 37 |
|
---|
| 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
|
---|
| 44 |
|
---|
| 45 | #define ICPS_BEGIN 0
|
---|
| 46 | #define ICPS_IPOPT 1
|
---|
| 47 | #define ICPS_MAIN 2
|
---|
| 48 | #define ICPS_ERROR 3
|
---|
| 49 |
|
---|
| 50 | PRIVATE icmp_port_t *icmp_port_table;
|
---|
| 51 |
|
---|
| 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,
|
---|
| 59 | acc_t *data ));
|
---|
| 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,
|
---|
| 76 | int ip_len ));
|
---|
| 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 ));
|
---|
| 86 | #endif
|
---|
| 87 |
|
---|
| 88 | PUBLIC void icmp_prep()
|
---|
| 89 | {
|
---|
| 90 | icmp_port_table= alloc(ip_conf_nr * sizeof(icmp_port_table[0]));
|
---|
| 91 | }
|
---|
| 92 |
|
---|
| 93 | PUBLIC void icmp_init()
|
---|
| 94 | {
|
---|
| 95 | int i;
|
---|
| 96 | icmp_port_t *icmp_port;
|
---|
| 97 |
|
---|
| 98 | assert (BUF_S >= sizeof (nwio_ipopt_t));
|
---|
| 99 |
|
---|
| 100 | for (i= 0, icmp_port= icmp_port_table; i<ip_conf_nr; i++, icmp_port++)
|
---|
| 101 | {
|
---|
| 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);
|
---|
| 109 | }
|
---|
| 110 |
|
---|
| 111 | #ifndef BUF_CONSISTENCY_CHECK
|
---|
| 112 | bf_logon(icmp_buffree);
|
---|
| 113 | #else
|
---|
| 114 | bf_logon(icmp_buffree, icmp_bufcheck);
|
---|
| 115 | #endif
|
---|
| 116 |
|
---|
| 117 | for (i= 0, icmp_port= icmp_port_table; i<ip_conf_nr; i++, icmp_port++)
|
---|
| 118 | {
|
---|
| 119 | icmp_main (icmp_port);
|
---|
| 120 | }
|
---|
| 121 | }
|
---|
| 122 |
|
---|
| 123 | PRIVATE void icmp_main(icmp_port)
|
---|
| 124 | icmp_port_t *icmp_port;
|
---|
| 125 | {
|
---|
| 126 | int result;
|
---|
| 127 | switch (icmp_port->icp_state)
|
---|
| 128 | {
|
---|
| 129 | case ICPS_BEGIN:
|
---|
| 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)
|
---|
| 135 | {
|
---|
| 136 | DBLOCK(1, printf("unable to open ip_port %d\n",
|
---|
| 137 | icmp_port->icp_ipport));
|
---|
| 138 | break;
|
---|
| 139 | }
|
---|
| 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)
|
---|
| 144 | {
|
---|
| 145 | icmp_port->icp_flags |= ICPF_SUSPEND;
|
---|
| 146 | break;
|
---|
| 147 | }
|
---|
| 148 | assert(result == NW_OK);
|
---|
| 149 |
|
---|
| 150 | /* falls through */
|
---|
| 151 | case ICPS_IPOPT:
|
---|
| 152 | icmp_port->icp_state= ICPS_MAIN;
|
---|
| 153 | icmp_port->icp_flags &= ~ICPF_SUSPEND;
|
---|
| 154 | icmp_read(icmp_port);
|
---|
| 155 | break;
|
---|
| 156 | default:
|
---|
| 157 | DBLOCK(1, printf("unknown state %d\n",
|
---|
| 158 | icmp_port->icp_state));
|
---|
| 159 | break;
|
---|
| 160 | }
|
---|
| 161 | }
|
---|
| 162 |
|
---|
| 163 | PRIVATE acc_t *icmp_getdata(port, offset, count, for_ioctl)
|
---|
| 164 | int port;
|
---|
| 165 | size_t offset, count;
|
---|
| 166 | int for_ioctl;
|
---|
| 167 | {
|
---|
| 168 | icmp_port_t *icmp_port;
|
---|
| 169 | nwio_ipopt_t *ipopt;
|
---|
| 170 | acc_t *data;
|
---|
| 171 | int result;
|
---|
| 172 | ev_arg_t ev_arg;
|
---|
| 173 |
|
---|
| 174 | icmp_port= &icmp_port_table[port];
|
---|
| 175 |
|
---|
| 176 | if (icmp_port->icp_flags & ICPF_WRITE_IP)
|
---|
| 177 | {
|
---|
| 178 | if (!count)
|
---|
| 179 | {
|
---|
| 180 | bf_afree(icmp_port->icp_write_pack);
|
---|
| 181 | icmp_port->icp_write_pack= 0;
|
---|
| 182 |
|
---|
| 183 | result= (int)offset;
|
---|
| 184 | if (result<0)
|
---|
| 185 | {
|
---|
| 186 | DBLOCK(1, printf("got write error %d\n",
|
---|
| 187 | result));
|
---|
| 188 | }
|
---|
| 189 | if (icmp_port->icp_flags & ICPF_WRITE_SP)
|
---|
| 190 | {
|
---|
| 191 | icmp_port->icp_flags &= ~ICPF_WRITE_SP;
|
---|
| 192 | ev_arg.ev_ptr= icmp_port;
|
---|
| 193 | ev_enqueue(&icmp_port->icp_event, icmp_write,
|
---|
| 194 | ev_arg);
|
---|
| 195 | }
|
---|
| 196 | return NW_OK;
|
---|
| 197 | }
|
---|
| 198 | return bf_cut(icmp_port->icp_write_pack, offset, count);
|
---|
| 199 | }
|
---|
| 200 | switch (icmp_port->icp_state)
|
---|
| 201 | {
|
---|
| 202 | case ICPS_IPOPT:
|
---|
| 203 | if (!count)
|
---|
| 204 | {
|
---|
| 205 | result= (int)offset;
|
---|
| 206 | assert(result == NW_OK);
|
---|
| 207 | if (result < 0)
|
---|
| 208 | {
|
---|
| 209 | icmp_port->icp_state= ICPS_ERROR;
|
---|
| 210 | break;
|
---|
| 211 | }
|
---|
| 212 | if (icmp_port->icp_flags & ICPF_SUSPEND)
|
---|
| 213 | icmp_main(icmp_port);
|
---|
| 214 | return NW_OK;
|
---|
| 215 | }
|
---|
| 216 |
|
---|
| 217 | data= bf_memreq (sizeof (*ipopt));
|
---|
| 218 | ipopt= (nwio_ipopt_t *)ptr2acc_data(data);
|
---|
| 219 | ipopt->nwio_flags= NWIO_COPY | NWIO_EN_LOC |
|
---|
| 220 | NWIO_EN_BROAD |
|
---|
| 221 | NWIO_REMANY | NWIO_PROTOSPEC |
|
---|
| 222 | NWIO_HDR_O_ANY | NWIO_RWDATALL;
|
---|
| 223 | ipopt->nwio_proto= IPPROTO_ICMP;
|
---|
| 224 | return data;
|
---|
| 225 | default:
|
---|
| 226 | break;
|
---|
| 227 | }
|
---|
| 228 | DBLOCK(1, printf("unknown state %d\n", icmp_port->icp_state));
|
---|
| 229 | return NULL;
|
---|
| 230 | }
|
---|
| 231 |
|
---|
| 232 | PRIVATE int icmp_putdata(port, offset, data, for_ioctl)
|
---|
| 233 | int port;
|
---|
| 234 | size_t offset;
|
---|
| 235 | acc_t *data;
|
---|
| 236 | int for_ioctl;
|
---|
| 237 | {
|
---|
| 238 | icmp_port_t *icmp_port;
|
---|
| 239 | int result;
|
---|
| 240 |
|
---|
| 241 | icmp_port= &icmp_port_table[port];
|
---|
| 242 |
|
---|
| 243 | if (icmp_port->icp_flags & ICPF_READ_IP)
|
---|
| 244 | {
|
---|
| 245 | if (!data)
|
---|
| 246 | {
|
---|
| 247 | result= (int)offset;
|
---|
| 248 | if (result<0)
|
---|
| 249 | {
|
---|
| 250 | DBLOCK(1, printf("got read error %d\n",
|
---|
| 251 | result));
|
---|
| 252 | }
|
---|
| 253 | if (icmp_port->icp_flags & ICPF_READ_SP)
|
---|
| 254 | {
|
---|
| 255 | icmp_port->icp_flags &=
|
---|
| 256 | ~(ICPF_READ_IP|ICPF_READ_SP);
|
---|
| 257 | icmp_read (icmp_port);
|
---|
| 258 | }
|
---|
| 259 | return NW_OK;
|
---|
| 260 | }
|
---|
| 261 | process_data(icmp_port, data);
|
---|
| 262 | return NW_OK;
|
---|
| 263 | }
|
---|
| 264 | switch (icmp_port->icp_state)
|
---|
| 265 | {
|
---|
| 266 | default:
|
---|
| 267 | DBLOCK(1, printf("unknown state %d\n",
|
---|
| 268 | icmp_port->icp_state));
|
---|
| 269 | return 0;
|
---|
| 270 | }
|
---|
| 271 | }
|
---|
| 272 |
|
---|
| 273 | PRIVATE void icmp_read(icmp_port)
|
---|
| 274 | icmp_port_t *icmp_port;
|
---|
| 275 | {
|
---|
| 276 | int result;
|
---|
| 277 |
|
---|
| 278 | for (;;)
|
---|
| 279 | {
|
---|
| 280 | icmp_port->icp_flags |= ICPF_READ_IP;
|
---|
| 281 | icmp_port->icp_flags &= ~ICPF_READ_SP;
|
---|
| 282 |
|
---|
| 283 | result= ip_read(icmp_port->icp_ipfd, ICMP_MAX_DATAGRAM);
|
---|
| 284 | if (result == NW_SUSPEND)
|
---|
| 285 | {
|
---|
| 286 | icmp_port->icp_flags |= ICPF_READ_SP;
|
---|
| 287 | return;
|
---|
| 288 | }
|
---|
| 289 | }
|
---|
| 290 | }
|
---|
| 291 |
|
---|
| 292 | PUBLIC void icmp_snd_time_exceeded(port_nr, pack, code)
|
---|
| 293 | int port_nr;
|
---|
| 294 | acc_t *pack;
|
---|
| 295 | int code;
|
---|
| 296 | {
|
---|
| 297 | icmp_hdr_t *icmp_hdr;
|
---|
| 298 | icmp_port_t *icmp_port;
|
---|
| 299 |
|
---|
| 300 | if (port_nr >= 0 && port_nr < ip_conf_nr)
|
---|
| 301 | icmp_port= &icmp_port_table[port_nr];
|
---|
| 302 | else
|
---|
| 303 | {
|
---|
| 304 | printf("icmp_snd_time_exceeded: strange port %d\n", port_nr);
|
---|
| 305 | bf_afree(pack);
|
---|
| 306 | return;
|
---|
| 307 | }
|
---|
| 308 | pack= icmp_err_pack(pack, &icmp_hdr);
|
---|
| 309 | if (pack == NULL)
|
---|
| 310 | return;
|
---|
| 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);
|
---|
| 316 | }
|
---|
| 317 |
|
---|
| 318 | PUBLIC void icmp_snd_redirect(port_nr, pack, code, gw)
|
---|
| 319 | int port_nr;
|
---|
| 320 | acc_t *pack;
|
---|
| 321 | int code;
|
---|
| 322 | ipaddr_t gw;
|
---|
| 323 | {
|
---|
| 324 | icmp_hdr_t *icmp_hdr;
|
---|
| 325 | icmp_port_t *icmp_port;
|
---|
| 326 |
|
---|
| 327 | if (port_nr >= 0 && port_nr < ip_conf_nr)
|
---|
| 328 | icmp_port= &icmp_port_table[port_nr];
|
---|
| 329 | else
|
---|
| 330 | {
|
---|
| 331 | printf("icmp_snd_redirect: strange port %d\n", port_nr);
|
---|
| 332 | bf_afree(pack);
|
---|
| 333 | return;
|
---|
| 334 | }
|
---|
| 335 | pack= icmp_err_pack(pack, &icmp_hdr);
|
---|
| 336 | if (pack == NULL)
|
---|
| 337 | return;
|
---|
| 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);
|
---|
| 346 | }
|
---|
| 347 |
|
---|
| 348 | PUBLIC void icmp_snd_unreachable(port_nr, pack, code)
|
---|
| 349 | int port_nr;
|
---|
| 350 | acc_t *pack;
|
---|
| 351 | int code;
|
---|
| 352 | {
|
---|
| 353 | icmp_hdr_t *icmp_hdr;
|
---|
| 354 | icmp_port_t *icmp_port;
|
---|
| 355 |
|
---|
| 356 | if (port_nr >= 0 && port_nr < ip_conf_nr)
|
---|
| 357 | icmp_port= &icmp_port_table[port_nr];
|
---|
| 358 | else
|
---|
| 359 | {
|
---|
| 360 | printf("icmp_snd_unreachable: strange port %d\n", port_nr);
|
---|
| 361 | bf_afree(pack);
|
---|
| 362 | return;
|
---|
| 363 | }
|
---|
| 364 | pack= icmp_err_pack(pack, &icmp_hdr);
|
---|
| 365 | if (pack == NULL)
|
---|
| 366 | return;
|
---|
| 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);
|
---|
| 372 | }
|
---|
| 373 |
|
---|
| 374 | PUBLIC void icmp_snd_mtu(port_nr, pack, mtu)
|
---|
| 375 | int port_nr;
|
---|
| 376 | acc_t *pack;
|
---|
| 377 | u16_t mtu;
|
---|
| 378 | {
|
---|
| 379 | icmp_hdr_t *icmp_hdr;
|
---|
| 380 | icmp_port_t *icmp_port;
|
---|
| 381 |
|
---|
| 382 | if (port_nr >= 0 && port_nr < ip_conf_nr)
|
---|
| 383 | icmp_port= &icmp_port_table[port_nr];
|
---|
| 384 | else
|
---|
| 385 | {
|
---|
| 386 | printf("icmp_snd_mtu: strange port %d\n", port_nr);
|
---|
| 387 | bf_afree(pack);
|
---|
| 388 | return;
|
---|
| 389 | }
|
---|
| 390 |
|
---|
| 391 | pack= icmp_err_pack(pack, &icmp_hdr);
|
---|
| 392 | if (pack == NULL)
|
---|
| 393 | return;
|
---|
| 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);
|
---|
| 402 | }
|
---|
| 403 |
|
---|
| 404 | PRIVATE void process_data(icmp_port, data)
|
---|
| 405 | icmp_port_t *icmp_port;
|
---|
| 406 | acc_t *data;
|
---|
| 407 | {
|
---|
| 408 | ip_hdr_t *ip_hdr;
|
---|
| 409 | icmp_hdr_t *icmp_hdr;
|
---|
| 410 | acc_t *icmp_data;
|
---|
| 411 | int ip_hdr_len;
|
---|
| 412 | size_t pack_len;
|
---|
| 413 |
|
---|
| 414 | /* Align entire packet */
|
---|
| 415 | data= bf_align(data, BUF_S, 4);
|
---|
| 416 |
|
---|
| 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;
|
---|
| 422 |
|
---|
| 423 | if (ip_hdr_len>IP_MIN_HDR_SIZE)
|
---|
| 424 | {
|
---|
| 425 | data= bf_packIffLess(data, ip_hdr_len);
|
---|
| 426 | ip_hdr= (ip_hdr_t *)ptr2acc_data(data);
|
---|
| 427 | }
|
---|
| 428 |
|
---|
| 429 | pack_len= bf_bufsize(data);
|
---|
| 430 | pack_len -= ip_hdr_len;
|
---|
| 431 | if (pack_len < ICMP_MIN_HDR_SIZE)
|
---|
| 432 | {
|
---|
| 433 | if (pack_len == 0 && ip_hdr->ih_proto == 0)
|
---|
| 434 | {
|
---|
| 435 | /* IP layer reports new ip address, which can be
|
---|
| 436 | * ignored.
|
---|
| 437 | */
|
---|
| 438 | }
|
---|
| 439 | else
|
---|
| 440 | DBLOCK(1, printf("got an incomplete icmp packet\n"));
|
---|
| 441 | bf_afree(data);
|
---|
| 442 | return;
|
---|
| 443 | }
|
---|
| 444 |
|
---|
| 445 | icmp_data= bf_cut(data, ip_hdr_len, pack_len);
|
---|
| 446 |
|
---|
| 447 | icmp_data= bf_packIffLess (icmp_data, ICMP_MIN_HDR_SIZE);
|
---|
| 448 | icmp_hdr= (icmp_hdr_t *)ptr2acc_data(icmp_data);
|
---|
| 449 |
|
---|
| 450 | if ((u16_t)~icmp_pack_oneCsum(icmp_data))
|
---|
| 451 | {
|
---|
| 452 | DBLOCK(1, printf(
|
---|
| 453 | "got packet with bad checksum (= 0x%x, 0x%x)\n",
|
---|
| 454 | icmp_hdr->ih_chksum,
|
---|
| 455 | (u16_t)~icmp_pack_oneCsum(icmp_data)));
|
---|
| 456 | bf_afree(data);
|
---|
| 457 | bf_afree(icmp_data);
|
---|
| 458 | return;
|
---|
| 459 | }
|
---|
| 460 |
|
---|
| 461 | switch (icmp_hdr->ih_type)
|
---|
| 462 | {
|
---|
| 463 | case ICMP_TYPE_ECHO_REPL:
|
---|
| 464 | break;
|
---|
| 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);
|
---|
| 468 | break;
|
---|
| 469 | case ICMP_TYPE_SRC_QUENCH:
|
---|
| 470 | /* Ignore src quench ICMPs */
|
---|
| 471 | DBLOCK(2, printf("ignoring SRC QUENCH ICMP.\n"));
|
---|
| 472 | break;
|
---|
| 473 | case ICMP_TYPE_REDIRECT:
|
---|
| 474 | icmp_redirect (icmp_port, ip_hdr, icmp_data, pack_len,
|
---|
| 475 | icmp_hdr);
|
---|
| 476 | break;
|
---|
| 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);
|
---|
| 480 | return;
|
---|
| 481 | case ICMP_TYPE_ROUTER_ADVER:
|
---|
| 482 | icmp_router_advertisement(icmp_port, icmp_data, pack_len,
|
---|
| 483 | icmp_hdr);
|
---|
| 484 | break;
|
---|
| 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);
|
---|
| 490 | break;
|
---|
| 491 | default:
|
---|
| 492 | DBLOCK(1, printf("got an unknown icmp (%d) from ",
|
---|
| 493 | icmp_hdr->ih_type);
|
---|
| 494 | writeIpAddr(ip_hdr->ih_src); printf("\n"));
|
---|
| 495 | break;
|
---|
| 496 | }
|
---|
| 497 | bf_afree(data);
|
---|
| 498 | bf_afree(icmp_data);
|
---|
| 499 | }
|
---|
| 500 |
|
---|
| 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;
|
---|
| 506 | ip_hdr_t *ip_hdr;
|
---|
| 507 | icmp_hdr_t *icmp_hdr;
|
---|
| 508 | {
|
---|
| 509 | acc_t *repl_ip_hdr, *repl_icmp;
|
---|
| 510 | ipaddr_t tmpaddr, locaddr, netmask;
|
---|
| 511 | icmp_hdr_t *repl_icmp_hdr;
|
---|
| 512 | i32_t tmp_chksum;
|
---|
| 513 | ip_port_t *ip_port;
|
---|
| 514 |
|
---|
| 515 | if (icmp_hdr->ih_code != 0)
|
---|
| 516 | {
|
---|
| 517 | DBLOCK(1,
|
---|
| 518 | printf("got an icmp echo request with unknown code (%d)\n",
|
---|
| 519 | icmp_hdr->ih_code));
|
---|
| 520 | bf_afree(ip_data);
|
---|
| 521 | bf_afree(icmp_data);
|
---|
| 522 | return;
|
---|
| 523 | }
|
---|
| 524 | if (icmp_len < ICMP_MIN_HDR_SIZE + sizeof(icmp_id_seq_t))
|
---|
| 525 | {
|
---|
| 526 | DBLOCK(1, printf("got an incomplete icmp echo request\n"));
|
---|
| 527 | bf_afree(ip_data);
|
---|
| 528 | bf_afree(icmp_data);
|
---|
| 529 | return;
|
---|
| 530 | }
|
---|
| 531 | tmpaddr= ntohl(ip_hdr->ih_dst);
|
---|
| 532 | if ((tmpaddr & 0xe0000000) == 0xe0000000 &&
|
---|
| 533 | tmpaddr != 0xffffffff)
|
---|
| 534 | {
|
---|
| 535 | /* Respond only to the all hosts multicast address until
|
---|
| 536 | * a decent listening service has been implemented
|
---|
| 537 | */
|
---|
| 538 | if (tmpaddr != 0xe0000001)
|
---|
| 539 | {
|
---|
| 540 | bf_afree(ip_data);
|
---|
| 541 | bf_afree(icmp_data);
|
---|
| 542 | return;
|
---|
| 543 | }
|
---|
| 544 | }
|
---|
| 545 |
|
---|
| 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)
|
---|
| 553 | {
|
---|
| 554 | /* Directed broadcast */
|
---|
| 555 | bf_afree(ip_data);
|
---|
| 556 | bf_afree(icmp_data);
|
---|
| 557 | return;
|
---|
| 558 | }
|
---|
| 559 |
|
---|
| 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;
|
---|
| 565 |
|
---|
| 566 | DBLOCK(2,
|
---|
| 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));
|
---|
| 577 |
|
---|
| 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);
|
---|
| 581 |
|
---|
| 582 | bf_afree(ip_data);
|
---|
| 583 | bf_afree(icmp_data);
|
---|
| 584 |
|
---|
| 585 | enqueue_pack(icmp_port, repl_ip_hdr);
|
---|
| 586 | }
|
---|
| 587 |
|
---|
| 588 | PRIVATE u16_t icmp_pack_oneCsum(icmp_pack)
|
---|
| 589 | acc_t *icmp_pack;
|
---|
| 590 | {
|
---|
| 591 | u16_t prev;
|
---|
| 592 | int odd_byte;
|
---|
| 593 | char *data_ptr;
|
---|
| 594 | int length;
|
---|
| 595 | char byte_buf[2];
|
---|
| 596 |
|
---|
| 597 | prev= 0;
|
---|
| 598 |
|
---|
| 599 | odd_byte= FALSE;
|
---|
| 600 | for (; icmp_pack; icmp_pack= icmp_pack->acc_next)
|
---|
| 601 | {
|
---|
| 602 | data_ptr= ptr2acc_data(icmp_pack);
|
---|
| 603 | length= icmp_pack->acc_length;
|
---|
| 604 |
|
---|
| 605 | if (!length)
|
---|
| 606 | continue;
|
---|
| 607 | if (odd_byte)
|
---|
| 608 | {
|
---|
| 609 | byte_buf[1]= *data_ptr;
|
---|
| 610 | prev= oneC_sum(prev, (u16_t *)byte_buf, 2);
|
---|
| 611 | data_ptr++;
|
---|
| 612 | length--;
|
---|
| 613 | odd_byte= FALSE;
|
---|
| 614 | }
|
---|
| 615 | if (length & 1)
|
---|
| 616 | {
|
---|
| 617 | odd_byte= TRUE;
|
---|
| 618 | length--;
|
---|
| 619 | byte_buf[0]= data_ptr[length];
|
---|
| 620 | }
|
---|
| 621 | if (!length)
|
---|
| 622 | continue;
|
---|
| 623 | prev= oneC_sum (prev, (u16_t *)data_ptr, length);
|
---|
| 624 | }
|
---|
| 625 | if (odd_byte)
|
---|
| 626 | prev= oneC_sum (prev, (u16_t *)byte_buf, 1);
|
---|
| 627 | return prev;
|
---|
| 628 | }
|
---|
| 629 |
|
---|
| 630 | PRIVATE acc_t *make_repl_ip(ip_hdr, ip_len)
|
---|
| 631 | ip_hdr_t *ip_hdr;
|
---|
| 632 | int ip_len;
|
---|
| 633 | {
|
---|
| 634 | ip_hdr_t *repl_ip_hdr;
|
---|
| 635 | acc_t *repl;
|
---|
| 636 | int repl_hdr_len;
|
---|
| 637 |
|
---|
| 638 | if (ip_len>IP_MIN_HDR_SIZE)
|
---|
| 639 | {
|
---|
| 640 | DBLOCK(1, printf("ip_hdr options NOT supported (yet?)\n"));
|
---|
| 641 | ip_len= IP_MIN_HDR_SIZE;
|
---|
| 642 | }
|
---|
| 643 |
|
---|
| 644 | repl_hdr_len= IP_MIN_HDR_SIZE;
|
---|
| 645 |
|
---|
| 646 | repl= bf_memreq(repl_hdr_len);
|
---|
| 647 |
|
---|
| 648 | repl_ip_hdr= (ip_hdr_t *)ptr2acc_data(repl);
|
---|
| 649 |
|
---|
| 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;
|
---|
| 656 |
|
---|
| 657 | return repl;
|
---|
| 658 | }
|
---|
| 659 |
|
---|
| 660 | PRIVATE void enqueue_pack(icmp_port, reply_ip_hdr)
|
---|
| 661 | icmp_port_t *icmp_port;
|
---|
| 662 | acc_t *reply_ip_hdr;
|
---|
| 663 | {
|
---|
| 664 | int r;
|
---|
| 665 | ev_arg_t ev_arg;
|
---|
| 666 |
|
---|
| 667 | /* Check rate */
|
---|
| 668 | if (icmp_port->icp_rate_count >= ICMP_MAX_RATE)
|
---|
| 669 | {
|
---|
| 670 | /* Something is going wrong; check policy */
|
---|
| 671 | r= icmp_rate_limit(icmp_port, reply_ip_hdr);
|
---|
| 672 | if (r == -1)
|
---|
| 673 | {
|
---|
| 674 | bf_afree(reply_ip_hdr);
|
---|
| 675 | reply_ip_hdr= NULL;
|
---|
| 676 | return;
|
---|
| 677 | }
|
---|
| 678 |
|
---|
| 679 | /* OK, continue */
|
---|
| 680 | }
|
---|
| 681 | icmp_port->icp_rate_count++;
|
---|
| 682 |
|
---|
| 683 | reply_ip_hdr->acc_ext_link= 0;
|
---|
| 684 |
|
---|
| 685 | if (icmp_port->icp_head_queue)
|
---|
| 686 | {
|
---|
| 687 | icmp_port->icp_tail_queue->acc_ext_link=
|
---|
| 688 | reply_ip_hdr;
|
---|
| 689 | }
|
---|
| 690 | else
|
---|
| 691 | {
|
---|
| 692 | icmp_port->icp_head_queue= reply_ip_hdr;
|
---|
| 693 | }
|
---|
| 694 | reply_ip_hdr->acc_ext_link= NULL;
|
---|
| 695 | icmp_port->icp_tail_queue= reply_ip_hdr;
|
---|
| 696 |
|
---|
| 697 | if (!(icmp_port->icp_flags & ICPF_WRITE_IP))
|
---|
| 698 | {
|
---|
| 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);
|
---|
| 702 | }
|
---|
| 703 | }
|
---|
| 704 |
|
---|
| 705 | PRIVATE int icmp_rate_limit(icmp_port, reply_ip_hdr)
|
---|
| 706 | icmp_port_t *icmp_port;
|
---|
| 707 | acc_t *reply_ip_hdr;
|
---|
| 708 | {
|
---|
| 709 | time_t t;
|
---|
| 710 | acc_t *pack;
|
---|
| 711 | ip_hdr_t *ip_hdr;
|
---|
| 712 | icmp_hdr_t *icmp_hdr;
|
---|
| 713 | int hdrlen, icmp_hdr_len, type;
|
---|
| 714 |
|
---|
| 715 | /* Check the time first */
|
---|
| 716 | t= get_time();
|
---|
| 717 | if (t >= icmp_port->icp_rate_lasttime + ICMP_RATE_INTERVAL)
|
---|
| 718 | {
|
---|
| 719 | icmp_port->icp_rate_lasttime= t;
|
---|
| 720 | icmp_port->icp_rate_count= 0;
|
---|
| 721 | return 0;
|
---|
| 722 | }
|
---|
| 723 |
|
---|
| 724 | icmp_port->icp_rate_count++;
|
---|
| 725 |
|
---|
| 726 | /* Adjust report limit if necessary */
|
---|
| 727 | if (icmp_port->icp_rate_count >
|
---|
| 728 | icmp_port->icp_rate_report+ICMP_RATE_WARN)
|
---|
| 729 | {
|
---|
| 730 | icmp_port->icp_rate_report *= 2;
|
---|
| 731 | return -1;
|
---|
| 732 | }
|
---|
| 733 |
|
---|
| 734 | /* Do we need to report */
|
---|
| 735 | if (icmp_port->icp_rate_count < icmp_port->icp_rate_report)
|
---|
| 736 | return -1;
|
---|
| 737 |
|
---|
| 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);
|
---|
| 750 | switch(type)
|
---|
| 751 | {
|
---|
| 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));
|
---|
| 767 | break;
|
---|
| 768 | default:
|
---|
| 769 | break;
|
---|
| 770 | }
|
---|
| 771 | bf_afree(pack); pack= NULL;
|
---|
| 772 |
|
---|
| 773 | return -1;
|
---|
| 774 | }
|
---|
| 775 |
|
---|
| 776 | PRIVATE void icmp_write(ev, ev_arg)
|
---|
| 777 | event_t *ev;
|
---|
| 778 | ev_arg_t ev_arg;
|
---|
| 779 | {
|
---|
| 780 | int result;
|
---|
| 781 | icmp_port_t *icmp_port;
|
---|
| 782 | acc_t *data;
|
---|
| 783 |
|
---|
| 784 | icmp_port= ev_arg.ev_ptr;
|
---|
| 785 | assert(ev == &icmp_port->icp_event);
|
---|
| 786 |
|
---|
| 787 | assert (icmp_port->icp_flags & ICPF_WRITE_IP);
|
---|
| 788 | assert (!(icmp_port->icp_flags & ICPF_WRITE_SP));
|
---|
| 789 |
|
---|
| 790 | while (icmp_port->icp_head_queue != NULL)
|
---|
| 791 | {
|
---|
| 792 | data= icmp_port->icp_head_queue;
|
---|
| 793 | icmp_port->icp_head_queue= data->acc_ext_link;
|
---|
| 794 |
|
---|
| 795 | result= ip_send(icmp_port->icp_ipfd, data,
|
---|
| 796 | bf_bufsize(data));
|
---|
| 797 | if (result != NW_WOULDBLOCK)
|
---|
| 798 | {
|
---|
| 799 | if (result == NW_OK)
|
---|
| 800 | continue;
|
---|
| 801 | DBLOCK(1, printf("icmp_write: error %d\n", result););
|
---|
| 802 | continue;
|
---|
| 803 | }
|
---|
| 804 |
|
---|
| 805 | assert(icmp_port->icp_write_pack == NULL);
|
---|
| 806 | icmp_port->icp_write_pack= data;
|
---|
| 807 |
|
---|
| 808 | result= ip_write(icmp_port->icp_ipfd,
|
---|
| 809 | bf_bufsize(icmp_port->icp_write_pack));
|
---|
| 810 | if (result == NW_SUSPEND)
|
---|
| 811 | {
|
---|
| 812 | icmp_port->icp_flags |= ICPF_WRITE_SP;
|
---|
| 813 | return;
|
---|
| 814 | }
|
---|
| 815 | }
|
---|
| 816 | icmp_port->icp_flags &= ~ICPF_WRITE_IP;
|
---|
| 817 | }
|
---|
| 818 |
|
---|
| 819 | PRIVATE void icmp_buffree(priority)
|
---|
| 820 | int priority;
|
---|
| 821 | {
|
---|
| 822 | acc_t *tmp_acc;
|
---|
| 823 | int i;
|
---|
| 824 | icmp_port_t *icmp_port;
|
---|
| 825 |
|
---|
| 826 | if (priority == ICMP_PRI_QUEUE)
|
---|
| 827 | {
|
---|
| 828 | for (i=0, icmp_port= icmp_port_table; i<ip_conf_nr;
|
---|
| 829 | i++, icmp_port++)
|
---|
| 830 | {
|
---|
| 831 | while(icmp_port->icp_head_queue)
|
---|
| 832 | {
|
---|
| 833 | tmp_acc= icmp_port->icp_head_queue;
|
---|
| 834 | icmp_port->icp_head_queue=
|
---|
| 835 | tmp_acc->acc_ext_link;
|
---|
| 836 | bf_afree(tmp_acc);
|
---|
| 837 | }
|
---|
| 838 | }
|
---|
| 839 | }
|
---|
| 840 | }
|
---|
| 841 |
|
---|
| 842 | #ifdef BUF_CONSISTENCY_CHECK
|
---|
| 843 | PRIVATE void icmp_bufcheck()
|
---|
| 844 | {
|
---|
| 845 | int i;
|
---|
| 846 | icmp_port_t *icmp_port;
|
---|
| 847 | acc_t *pack;
|
---|
| 848 |
|
---|
| 849 | for (i= 0, icmp_port= icmp_port_table; i<ip_conf_nr; i++, icmp_port++)
|
---|
| 850 | {
|
---|
| 851 | for (pack= icmp_port->icp_head_queue; pack;
|
---|
| 852 | pack= pack->acc_ext_link)
|
---|
| 853 | {
|
---|
| 854 | bf_check_acc(pack);
|
---|
| 855 | }
|
---|
| 856 | bf_check_acc(icmp_port->icp_write_pack);
|
---|
| 857 | }
|
---|
| 858 | }
|
---|
| 859 | #endif
|
---|
| 860 |
|
---|
| 861 | PRIVATE void icmp_dst_unreach(icmp_port, ip_pack, ip_hdr_len, ip_hdr, icmp_pack,
|
---|
| 862 | icmp_len, icmp_hdr)
|
---|
| 863 | icmp_port_t *icmp_port;
|
---|
| 864 | acc_t *ip_pack;
|
---|
| 865 | int ip_hdr_len;
|
---|
| 866 | ip_hdr_t *ip_hdr;
|
---|
| 867 | acc_t *icmp_pack;
|
---|
| 868 | int icmp_len;
|
---|
| 869 | icmp_hdr_t *icmp_hdr;
|
---|
| 870 | {
|
---|
| 871 | acc_t *old_ip_pack;
|
---|
| 872 | ip_hdr_t *old_ip_hdr;
|
---|
| 873 | int ip_port_nr;
|
---|
| 874 | ipaddr_t dst, mask;
|
---|
| 875 | size_t old_pack_size;
|
---|
| 876 | u16_t new_mtu;
|
---|
| 877 |
|
---|
| 878 | if (icmp_len < 8 + IP_MIN_HDR_SIZE)
|
---|
| 879 | {
|
---|
| 880 | DBLOCK(1, printf("dest unrch with wrong size\n"));
|
---|
| 881 | return;
|
---|
| 882 | }
|
---|
| 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);
|
---|
| 886 |
|
---|
| 887 | if (old_ip_hdr->ih_src != ip_hdr->ih_dst)
|
---|
| 888 | {
|
---|
| 889 | DBLOCK(1, printf("dest unrch based on wrong packet\n"));
|
---|
| 890 | bf_afree(old_ip_pack);
|
---|
| 891 | return;
|
---|
| 892 | }
|
---|
| 893 |
|
---|
| 894 | ip_port_nr= icmp_port->icp_ipport;
|
---|
| 895 |
|
---|
| 896 | switch(icmp_hdr->ih_code)
|
---|
| 897 | {
|
---|
| 898 | case ICMP_NET_UNRCH:
|
---|
| 899 | dst= old_ip_hdr->ih_dst;
|
---|
| 900 | mask= ip_get_netmask(dst);
|
---|
| 901 | ipr_destunrch (ip_port_nr, dst & mask, mask,
|
---|
| 902 | IPR_UNRCH_TIMEOUT);
|
---|
| 903 | break;
|
---|
| 904 | case ICMP_HOST_UNRCH:
|
---|
| 905 | ipr_destunrch (ip_port_nr, old_ip_hdr->ih_dst, (ipaddr_t)-1,
|
---|
| 906 | IPR_UNRCH_TIMEOUT);
|
---|
| 907 | break;
|
---|
| 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.
|
---|
| 911 | */
|
---|
| 912 | break;
|
---|
| 913 | case ICMP_FRAGM_AND_DF:
|
---|
| 914 |
|
---|
| 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);
|
---|
| 922 | if (!old_pack_size)
|
---|
| 923 | break;
|
---|
| 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,
|
---|
| 928 | IPR_MTU_TIMEOUT);
|
---|
| 929 | break;
|
---|
| 930 |
|
---|
| 931 | default:
|
---|
| 932 | DBLOCK(1, printf("icmp_dst_unreach: got strange code %d from ",
|
---|
| 933 | icmp_hdr->ih_code);
|
---|
| 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));
|
---|
| 939 | break;
|
---|
| 940 | }
|
---|
| 941 | bf_afree(old_ip_pack);
|
---|
| 942 | }
|
---|
| 943 |
|
---|
| 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;
|
---|
| 947 | acc_t *ip_pack;
|
---|
| 948 | int ip_hdr_len;
|
---|
| 949 | ip_hdr_t *ip_hdr;
|
---|
| 950 | acc_t *icmp_pack;
|
---|
| 951 | int icmp_len;
|
---|
| 952 | icmp_hdr_t *icmp_hdr;
|
---|
| 953 | {
|
---|
| 954 | acc_t *old_ip_pack;
|
---|
| 955 | ip_hdr_t *old_ip_hdr;
|
---|
| 956 | int ip_port_nr;
|
---|
| 957 |
|
---|
| 958 | if (icmp_len < 8 + IP_MIN_HDR_SIZE)
|
---|
| 959 | {
|
---|
| 960 | DBLOCK(1, printf("time exceeded with wrong size\n"));
|
---|
| 961 | return;
|
---|
| 962 | }
|
---|
| 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);
|
---|
| 966 |
|
---|
| 967 | if (old_ip_hdr->ih_src != ip_hdr->ih_dst)
|
---|
| 968 | {
|
---|
| 969 | DBLOCK(1, printf("time exceeded based on wrong packet\n"));
|
---|
| 970 | bf_afree(old_ip_pack);
|
---|
| 971 | return;
|
---|
| 972 | }
|
---|
| 973 |
|
---|
| 974 | ip_port_nr= icmp_port->icp_ipport;
|
---|
| 975 |
|
---|
| 976 | switch(icmp_hdr->ih_code)
|
---|
| 977 | {
|
---|
| 978 | case ICMP_TTL_EXC:
|
---|
| 979 | ipr_ttl_exc (ip_port_nr, old_ip_hdr->ih_dst, (ipaddr_t)-1,
|
---|
| 980 | IPR_TTL_TIMEOUT);
|
---|
| 981 | break;
|
---|
| 982 | case ICMP_FRAG_REASSEM:
|
---|
| 983 | /* Ignore reassembly time-outs. */
|
---|
| 984 | break;
|
---|
| 985 | default:
|
---|
| 986 | DBLOCK(1, printf("got strange code: %d\n",
|
---|
| 987 | icmp_hdr->ih_code));
|
---|
| 988 | break;
|
---|
| 989 | }
|
---|
| 990 | bf_afree(old_ip_pack);
|
---|
| 991 | }
|
---|
| 992 |
|
---|
| 993 | PRIVATE void icmp_router_advertisement(icmp_port, icmp_pack, icmp_len, icmp_hdr)
|
---|
| 994 | icmp_port_t *icmp_port;
|
---|
| 995 | acc_t *icmp_pack;
|
---|
| 996 | int icmp_len;
|
---|
| 997 | icmp_hdr_t *icmp_hdr;
|
---|
| 998 | {
|
---|
| 999 | int entries;
|
---|
| 1000 | int entry_size;
|
---|
| 1001 | u32_t addr;
|
---|
| 1002 | i32_t pref;
|
---|
| 1003 | u16_t lifetime;
|
---|
| 1004 | int i;
|
---|
| 1005 | char *bufp;
|
---|
| 1006 | ip_port_t *ip_port;
|
---|
| 1007 |
|
---|
| 1008 | if (icmp_len < 8)
|
---|
| 1009 | {
|
---|
| 1010 | DBLOCK(1,
|
---|
| 1011 | printf("router advertisement with wrong size (%d)\n",
|
---|
| 1012 | icmp_len));
|
---|
| 1013 | return;
|
---|
| 1014 | }
|
---|
| 1015 | if (icmp_hdr->ih_code != 0)
|
---|
| 1016 | {
|
---|
| 1017 | DBLOCK(1,
|
---|
| 1018 | printf("router advertisement with wrong code (%d)\n",
|
---|
| 1019 | icmp_hdr->ih_code));
|
---|
| 1020 | return;
|
---|
| 1021 | }
|
---|
| 1022 | entries= icmp_hdr->ih_hun.ihh_ram.iram_na;
|
---|
| 1023 | entry_size= icmp_hdr->ih_hun.ihh_ram.iram_aes * 4;
|
---|
| 1024 | if (entries < 1)
|
---|
| 1025 | {
|
---|
| 1026 | DBLOCK(1, printf(
|
---|
| 1027 | "router advertisement with wrong number of entries (%d)\n",
|
---|
| 1028 | entries));
|
---|
| 1029 | return;
|
---|
| 1030 | }
|
---|
| 1031 | if (entry_size < 8)
|
---|
| 1032 | {
|
---|
| 1033 | DBLOCK(1, printf(
|
---|
| 1034 | "router advertisement with wrong entry size (%d)\n",
|
---|
| 1035 | entry_size));
|
---|
| 1036 | return;
|
---|
| 1037 | }
|
---|
| 1038 | if (icmp_len < 8 + entries * entry_size)
|
---|
| 1039 | {
|
---|
| 1040 | DBLOCK(1,
|
---|
| 1041 | printf("router advertisement with wrong size\n");
|
---|
| 1042 | printf(
|
---|
| 1043 | "\t(entries= %d, entry_size= %d, icmp_len= %d)\n",
|
---|
| 1044 | entries, entry_size, icmp_len));
|
---|
| 1045 | return;
|
---|
| 1046 | }
|
---|
| 1047 | lifetime= ntohs(icmp_hdr->ih_hun.ihh_ram.iram_lt);
|
---|
| 1048 | if (lifetime > 9000)
|
---|
| 1049 | {
|
---|
| 1050 | DBLOCK(1, printf(
|
---|
| 1051 | "router advertisement with wrong lifetime (%d)\n",
|
---|
| 1052 | lifetime));
|
---|
| 1053 | return;
|
---|
| 1054 | }
|
---|
| 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++,
|
---|
| 1057 | bufp += entry_size)
|
---|
| 1058 | {
|
---|
| 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);
|
---|
| 1064 | }
|
---|
| 1065 | }
|
---|
| 1066 |
|
---|
| 1067 | PRIVATE void icmp_redirect(icmp_port, ip_hdr, icmp_pack, icmp_len, icmp_hdr)
|
---|
| 1068 | icmp_port_t *icmp_port;
|
---|
| 1069 | ip_hdr_t *ip_hdr;
|
---|
| 1070 | acc_t *icmp_pack;
|
---|
| 1071 | int icmp_len;
|
---|
| 1072 | icmp_hdr_t *icmp_hdr;
|
---|
| 1073 | {
|
---|
| 1074 | acc_t *old_ip_pack;
|
---|
| 1075 | ip_hdr_t *old_ip_hdr;
|
---|
| 1076 | int ip_port_nr;
|
---|
| 1077 | ipaddr_t dst, mask;
|
---|
| 1078 |
|
---|
| 1079 | if (icmp_len < 8 + IP_MIN_HDR_SIZE)
|
---|
| 1080 | {
|
---|
| 1081 | DBLOCK(1, printf("redirect with wrong size\n"));
|
---|
| 1082 | return;
|
---|
| 1083 | }
|
---|
| 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);
|
---|
| 1087 |
|
---|
| 1088 | ip_port_nr= icmp_port->icp_ipport;
|
---|
| 1089 |
|
---|
| 1090 | switch(icmp_hdr->ih_code)
|
---|
| 1091 | {
|
---|
| 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);
|
---|
| 1098 | break;
|
---|
| 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);
|
---|
| 1103 | break;
|
---|
| 1104 | default:
|
---|
| 1105 | DBLOCK(1, printf("got strange code: %d\n",
|
---|
| 1106 | icmp_hdr->ih_code));
|
---|
| 1107 | break;
|
---|
| 1108 | }
|
---|
| 1109 | bf_afree(old_ip_pack);
|
---|
| 1110 | }
|
---|
| 1111 |
|
---|
| 1112 | PRIVATE acc_t *icmp_err_pack(pack, icmp_hdr_pp)
|
---|
| 1113 | acc_t *pack;
|
---|
| 1114 | icmp_hdr_t **icmp_hdr_pp;
|
---|
| 1115 | {
|
---|
| 1116 | ip_hdr_t *ip_hdr;
|
---|
| 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;
|
---|
| 1122 | nettype_t nettype;
|
---|
| 1123 |
|
---|
| 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);
|
---|
| 1128 |
|
---|
| 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.
|
---|
| 1132 | */
|
---|
| 1133 | if ((ntohs(ip_hdr->ih_flags_fragoff) & IH_FRAGOFF_MASK) != 0)
|
---|
| 1134 | {
|
---|
| 1135 | bf_afree(pack);
|
---|
| 1136 | return NULL;
|
---|
| 1137 | }
|
---|
| 1138 | if (ip_hdr->ih_proto == IPPROTO_ICMP)
|
---|
| 1139 | {
|
---|
| 1140 | if (ip_hdr_len>IP_MIN_HDR_SIZE)
|
---|
| 1141 | {
|
---|
| 1142 | pack= bf_packIffLess(pack, ip_hdr_len);
|
---|
| 1143 | ip_hdr= (ip_hdr_t *)ptr2acc_data(pack);
|
---|
| 1144 | }
|
---|
| 1145 |
|
---|
| 1146 | if (pack_len < ip_hdr_len+ICMP_MIN_HDR_SIZE)
|
---|
| 1147 | {
|
---|
| 1148 | bf_afree(pack);
|
---|
| 1149 | return NULL;
|
---|
| 1150 | }
|
---|
| 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;
|
---|
| 1156 |
|
---|
| 1157 | if (ih_type != ICMP_TYPE_ECHO_REQ &&
|
---|
| 1158 | ih_type != ICMP_TYPE_ECHO_REPL)
|
---|
| 1159 | {
|
---|
| 1160 | bf_afree(pack);
|
---|
| 1161 | return NULL;
|
---|
| 1162 | }
|
---|
| 1163 | }
|
---|
| 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)
|
---|
| 1169 | {
|
---|
| 1170 | printf("icmp_err_pack: invalid source address: ");
|
---|
| 1171 | writeIpAddr(dest);
|
---|
| 1172 | printf("\n");
|
---|
| 1173 | bf_afree(pack);
|
---|
| 1174 | return NULL;
|
---|
| 1175 | }
|
---|
| 1176 |
|
---|
| 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)
|
---|
| 1180 | {
|
---|
| 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);
|
---|
| 1184 | bf_afree(pack);
|
---|
| 1185 | return NULL;
|
---|
| 1186 | }
|
---|
| 1187 | if (ip_hdr_len + 8 < size)
|
---|
| 1188 | size= ip_hdr_len+8;
|
---|
| 1189 | tmp_pack= bf_cut(pack, 0, size);
|
---|
| 1190 | bf_afree(pack);
|
---|
| 1191 | pack= tmp_pack;
|
---|
| 1192 | tmp_pack= NULL;
|
---|
| 1193 |
|
---|
| 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;
|
---|
| 1207 |
|
---|
| 1208 | /* Create an IP header */
|
---|
| 1209 | ip_hdr_len= IP_MIN_HDR_SIZE;
|
---|
| 1210 |
|
---|
| 1211 | ip_pack= bf_memreq(ip_hdr_len);
|
---|
| 1212 | ip_hdr= (ip_hdr_t *)ptr2acc_data(ip_pack);
|
---|
| 1213 |
|
---|
| 1214 | ip_hdr->ih_vers_ihl= ip_hdr_len >> 2;
|
---|
| 1215 | ip_hdr->ih_tos= 0;
|
---|
| 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;
|
---|
| 1221 |
|
---|
| 1222 | assert(ip_pack->acc_next == NULL);
|
---|
| 1223 | ip_pack->acc_next= pack;
|
---|
| 1224 | return ip_pack;
|
---|
| 1225 | }
|
---|
| 1226 |
|
---|
| 1227 | /*
|
---|
| 1228 | * $PchId: icmp.c,v 1.23 2005/06/28 14:16:56 philip Exp $
|
---|
| 1229 | */
|
---|