📄 arpresponder.cc
字号:
// -*- c-basic-offset: 4 -*-/* * arpresponder.{cc,hh} -- element that responds to ARP queries * Robert Morris * * Copyright (c) 1999-2000 Massachusetts Institute of Technology * * 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 "arpresponder.hh"#include <clicknet/ether.h>#include <click/etheraddress.hh>#include <click/ipaddress.hh>#include <click/confparse.hh>#include <click/error.hh>#include <click/glue.hh>#include <click/straccum.hh>CLICK_DECLSARPResponder::ARPResponder() : Element(1, 1){}ARPResponder::~ARPResponder(){}voidARPResponder::add_map(IPAddress ipa, IPAddress mask, EtherAddress ena){ struct Entry e; e.dst = ipa & mask; e.mask = mask; e.ena = ena; _v.push_back(e);}intARPResponder::configure(Vector<String> &conf, ErrorHandler *errh){ _v.clear(); int before = errh->nerrors(); for (int i = 0; i < conf.size(); i++) { IPAddress ipa, mask; EtherAddress ena; bool have_ena = false; int first = _v.size(); Vector<String> words; cp_spacevec(conf[i], words); for (int j = 0; j < words.size(); j++) if (cp_ip_address(words[j], &ipa, this)) add_map(ipa, IPAddress(0xFFFFFFFFU), EtherAddress()); else if (cp_ip_prefix(words[j], &ipa, &mask, this)) add_map(ipa, mask, EtherAddress()); else if (cp_ethernet_address(words[j], &ena, this)) { if (have_ena) errh->error("argument %d has more than one Ethernet address", i); have_ena = true; } else { errh->error("argument %d should be `IP/MASK ETHADDR'", i); j = words.size(); } // check for an argument that is both IP address and Ethernet address for (int j = 0; !have_ena && j < words.size(); j++) if (cp_ethernet_address(words[j], &ena, this)) have_ena = true; if (first == _v.size()) errh->error("argument %d had no IP address and masks", i); if (!have_ena) errh->error("argument %d had no Ethernet addresses", i); for (int j = first; j < _v.size(); j++) _v[j].ena = ena; } return (before == errh->nerrors() ? 0 : -1);}intARPResponder::live_reconfigure(Vector<String> &conf, ErrorHandler *errh){ // Copy the old mappings to a temporary vector Vector<Entry> old_v = _v; // if the configuration fails copy the old mapping vector back if (configure(conf, errh) < 0) { _v = old_v; return -1; } else return 0;}Packet *ARPResponder::make_response(u_char tha[6], /* him */ u_char tpa[4], u_char sha[6], /* me */ u_char spa[4], Packet *p /* only used for annotations */){ WritablePacket *q = Packet::make(sizeof(click_ether) + sizeof(click_ether_arp)); if (q == 0) { click_chatter("in arp responder: cannot make packet!"); return 0; } // in case of FromLinux, set the device annotation: want to make it seem // that ARP response came from the device that the query arrived on q->set_device_anno(p->device_anno()); memset(q->data(), '\0', q->length()); click_ether *e = (click_ether *) q->data(); q->set_ether_header(e); memcpy(e->ether_dhost, tha, 6); memcpy(e->ether_shost, sha, 6); e->ether_type = htons(ETHERTYPE_ARP); click_ether_arp *ea = (click_ether_arp *) (e + 1); ea->ea_hdr.ar_hrd = htons(ARPHRD_ETHER); ea->ea_hdr.ar_pro = htons(ETHERTYPE_IP); ea->ea_hdr.ar_hln = 6; ea->ea_hdr.ar_pln = 4; ea->ea_hdr.ar_op = htons(ARPOP_REPLY); memcpy(ea->arp_tha, tha, 6); memcpy(ea->arp_tpa, tpa, 4); memcpy(ea->arp_sha, sha, 6); memcpy(ea->arp_spa, spa, 4); return q;}boolARPResponder::lookup(IPAddress a, EtherAddress &ena) const{ int best = -1; for (int i = 0; i < _v.size(); i++) if (a.matches_prefix(_v[i].dst, _v[i].mask)) { if (best < 0 || _v[i].mask.mask_as_specific(_v[best].mask)) best = i; } if (best < 0) return false; else { ena = _v[best].ena; return true; }}Packet *ARPResponder::simple_action(Packet *p){ click_ether *e = (click_ether *) p->data(); click_ether_arp *ea = (click_ether_arp *) (e + 1); unsigned int tpa; memcpy(&tpa, ea->arp_tpa, 4); IPAddress ipa = IPAddress(tpa); Packet *q = 0; if (p->length() >= sizeof(*e) + sizeof(click_ether_arp) && ntohs(e->ether_type) == ETHERTYPE_ARP && ntohs(ea->ea_hdr.ar_hrd) == ARPHRD_ETHER && ntohs(ea->ea_hdr.ar_pro) == ETHERTYPE_IP && ntohs(ea->ea_hdr.ar_op) == ARPOP_REQUEST) { EtherAddress ena; if (lookup(ipa, ena)) { q = make_response(ea->arp_sha, ea->arp_spa, ena.data(), ea->arp_tpa, p); } } else { struct in_addr ina; memcpy(&ina, &ea->arp_tpa, 4); } p->kill(); return(q);}StringARPResponder::read_handler(Element *e, void *thunk){ ARPResponder *ar = static_cast<ARPResponder *>(e); switch ((intptr_t)thunk) { case 0: { // table StringAccum sa; for (int i = 0; i < ar->_v.size(); i++) sa << ar->_v[i].dst.unparse_with_mask(ar->_v[i].mask) << ' ' << ar->_v[i].ena << '\n'; return sa.take_string(); } default: return "<error>\n"; }}voidARPResponder::add_handlers(){ add_read_handler("table", read_handler, (void *)0);}EXPORT_ELEMENT(ARPResponder)// generate Vector template instance#include <click/vector.cc>#if EXPLICIT_TEMPLATE_INSTANCEStemplate class Vector<ARPResponder::Entry>;#endifCLICK_ENDDECLS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -