📄 icmperror.cc
字号:
/* * icmperror.{cc,hh} -- element constructs ICMP error packets * Robert Morris, Eddie Kohler * * Copyright (c) 1999-2000 Massachusetts Institute of Technology * Copyright (c) 2003 International Computer Science Institute * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, subject to the conditions * listed in the Click LICENSE file. These conditions include: you must * preserve this copyright notice, and you cannot mention the copyright * holders in advertising related to the Software without their permission. * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This * notice is a summary of the Click LICENSE file; the license in that file is * legally binding. */#include <click/config.h>#include <clicknet/icmp.h>#include <clicknet/ip.h>#include "icmperror.hh"#include <click/ipaddress.hh>#include <click/confparse.hh>#include <click/error.hh>#include <click/glue.hh>#include <click/packet_anno.hh>#include <click/nameinfo.hh>CLICK_DECLSICMPError::ICMPError() : Element(1, 1), _type(-1), _code(-1){}ICMPError::~ICMPError(){}boolICMPError::is_error_type(int type){ return type == ICMP_UNREACH || type == ICMP_SOURCEQUENCH || type == ICMP_REDIRECT || type == ICMP_TIMXCEED || type == ICMP_PARAMPROB;}intICMPError::configure(Vector<String> &conf, ErrorHandler *errh){ String code_str = "0"; _mtu = 576; _pmtu = 0; if (cp_va_parse(conf, this, errh, cpIPAddress, "source IP address", &_src_ip, cpNamedInteger, "ICMP error type", NameInfo::T_ICMP_TYPE, &_type, cpOptional, cpWord, "ICMP error code", &code_str, cpIPAddressList, "bad IP addresses", &_bad_addrs, cpKeywords, "BADADDRS", cpIPAddressList, "bad IP addresses", &_bad_addrs, "MTU", cpUnsigned, "MTU", &_mtu, "PMTU", cpUnsigned, "Next-Hop MTU", &_pmtu, cpEnd) < 0) return -1; if (_type < 0 || _type > 255) return errh->error("ICMP type must be between 0 and 255"); else if (!is_error_type(_type)) return errh->error("ICMP type %d is not an error type", _type); if (!NameInfo::query_int(NameInfo::T_ICMP_CODE + _type, this, code_str, &_code) || _code < 0 || _code > 255) return errh->error("argument 2 takes ICMP code (integer between 0 and 255)"); return 0;}/* * Is an IP address unicast? */boolICMPError::unicast(struct in_addr aa) const{ uint32_t a = aa.s_addr; uint32_t ha = ntohl(a); /* limited broadcast */ if(ha == 0xffffffff) return(0); /* Class D multicast */ if((ha & 0xf0000000u) == 0xe0000000u) return(0); /* limited broadcast */ if (_bad_addrs.contains(a)) return 0; return(1);}/* * Is a source IP address valid as defined in RFC1812 5.3.7 * or 4.2.2.11 or 4.2.3.1? */boolICMPError::valid_source(struct in_addr aa) const{ unsigned int a = aa.s_addr; unsigned int ha = ntohl(a); unsigned net = (ha >> 24) & 0xff; /* broadcast, multicast, or (local) directed broadcast */ if(unicast(aa) == 0) return(0); /* local net or host: */ if(net == 0) return(0); /* 127.0.0.1 */ if(net == 127) return(0); /* Class E */ if((net & 0xf0) == 0xf0) return(0); return(1);}/* * Does a packet contain a source route option? */const uint8_t *ICMPError::valid_source_route(const click_ip *iph){ const uint8_t *oa = (const uint8_t *)iph; int hlen = iph->ip_hl << 2; for (int oi = sizeof(click_ip); oi < hlen; ) { // handle one-byte options unsigned type = oa[oi]; if (type == IPOPT_NOP) { oi++; continue; } else if (type == IPOPT_EOL) return 0; // otherwise, get option length int xlen = oa[oi + 1]; if (xlen < 2 || oi + xlen > hlen) return 0; else if ((type == IPOPT_LSRR || type == IPOPT_SSRR) && oa[oi + 2] >= 4 && oa[oi + 2] % 4 == 0 && oa[oi + 2] <= xlen + 1) return oa + oi; else oi += xlen; } return 0;}Packet *ICMPError::simple_action(Packet *p){ WritablePacket *q = 0; const click_ip *ipp = p->ip_header(); const uint8_t *source_route; click_ip *nip; click_icmp *icp; unsigned hlen, xlen; static int id = 1; if (!ipp) goto out; hlen = ipp->ip_hl << 2; /* These "don'ts" are from RFC1812 4.3.2.7: */ /* Don't reply to ICMP error messages. */ if(ipp->ip_p == IP_PROTO_ICMP) { const click_icmp *icmph = p->icmp_header(); if(hlen + 4 > p->length() || is_error_type(icmph->icmp_type)) goto out; } /* Don't respond to packets with IP broadcast destinations. */ if(!unicast(ipp->ip_dst)) goto out; /* Don't respond to e.g. Ethernet broadcasts or multicasts. */ if (p->packet_type_anno() == Packet::BROADCAST || p->packet_type_anno() == Packet::MULTICAST) goto out; /* Don't respond is src is net 0 or invalid. */ if(!valid_source(ipp->ip_src)) goto out; /* Don't respond to fragments other than the first. */ if(!IP_FIRSTFRAG(ipp)) goto out; source_route = valid_source_route(ipp); if (source_route) { /* Don't send a redirect for a source-routed packet. 5.2.7.2 */ if (_type == ICMP_REDIRECT) goto out; /* Ignore source route if ICMP Parameter Problem concerns the source route. 4.3.2.6 */ if (_type == ICMP_PARAMPROB && _code == ICMP_PARAMPROB_ERRATPTR && source_route <= ((const uint8_t *)ipp + ICMP_PARAMPROB_ANNO(p)) && ((const uint8_t *)ipp + ICMP_PARAMPROB_ANNO(p)) < (source_route + source_route[1])) source_route = 0; } // maximum size of ICMP packet is 576 bytes. 4.3.2.3 q = Packet::make(_mtu); // we made it configurable if (!q) goto out; // prepare IP header; guaranteed that packet data is aligned nip = reinterpret_cast<click_ip *>(q->data()); nip->ip_v = 4; nip->ip_tos = 0; // XXX should be same as incoming datagram? nip->ip_id = htons(id++); nip->ip_off = 0; nip->ip_ttl = 200; nip->ip_p = IP_PROTO_ICMP; nip->ip_sum = 0; nip->ip_src = _src_ip.in_addr(); nip->ip_dst = ipp->ip_src; // include reversed source route if appropriate 4.3.2.6 if (source_route) { uint8_t *o = q->data() + sizeof(click_ip); int olen = source_route[2] - 1; o[0] = source_route[0]; // copy option type o[1] = olen; o[2] = 4; o[olen] = IPOPT_EOL; o += 3; for (const uint8_t *oo = source_route + source_route[2] - 5; oo >= source_route + 3; oo -= 4, o += 4) memcpy(o, oo, 4); nip->ip_hl = (sizeof(click_ip) + olen + 3) >> 2; } else nip->ip_hl = sizeof(click_ip) >> 2; q->set_ip_header(nip, nip->ip_hl << 2); // now, prepare ICMP header icp = q->icmp_header(); icp->icmp_type = _type; icp->icmp_code = _code; icp->icmp_cksum = 0; icp->padding = 0; // set ICMP particulars if (_type == ICMP_PARAMPROB && _code == ICMP_PARAMPROB_ERRATPTR) /* Set the Parameter Problem pointer. */ ((click_icmp_paramprob *) icp)->icmp_pointer = ICMP_PARAMPROB_ANNO(p); if (_type == ICMP_REDIRECT) ((click_icmp_redirect *) icp)->icmp_gateway = p->dst_ip_anno(); if (_type == ICMP_UNREACH && _code == ICMP_UNREACH_NEEDFRAG) ((click_icmp_needfrag *) icp)->icmp_nextmtu = htons(_pmtu); // copy packet contents xlen = q->end_data() - (uint8_t *)(icp + 1); if ((int)xlen > p->network_length()) { q->take(xlen - p->network_length()); xlen = p->network_length(); } memcpy((uint8_t *)(icp + 1), p->network_header(), xlen); icp->icmp_cksum = click_in_cksum((unsigned char *)icp, sizeof(click_icmp) + xlen); // finish off IP header nip->ip_len = htons(q->length()); nip->ip_sum = click_in_cksum((unsigned char *)nip, nip->ip_hl << 2); // set annotations q->set_dst_ip_anno(IPAddress(nip->ip_dst)); SET_FIX_IP_SRC_ANNO(q, 1); q->timestamp_anno().set_now(); out: p->kill(); return(q);}CLICK_ENDDECLSEXPORT_ELEMENT(ICMPError)ELEMENT_MT_SAFE(ICMPError)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -