ipnameinfo.cc

来自「Click is a modular router toolkit. To us」· CC 代码 · 共 374 行

CC
374
字号
/* * ipnameinfo.{cc,hh} -- element stores IP name-to-number mappings * Eddie Kohler * * Copyright (c) 2005 Regents of the University of California * * 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 "ipnameinfo.hh"#include <click/nameinfo.hh>#include <click/confparse.hh>#include <click/hashmap.hh>#include <clicknet/ip.h>#include <clicknet/icmp.h>#include <clicknet/tcp.h>#include <clicknet/udp.h>#if CLICK_USERLEVEL && HAVE_NETDB_H# include <netdb.h># include <click/userutils.hh># ifndef _PATH_PROTOCOLS#  define _PATH_PROTOCOLS "/etc/protocols"# endif# ifndef _PATH_SERVICES#  define _PATH_SERVICES "/etc/services"# endif#endifCLICK_DECLSstatic const StaticNameDB::Entry ip_protos[] = {    { "dccp", IP_PROTO_DCCP },    { "icmp", IP_PROTO_ICMP },    { "igmp", IP_PROTO_IGMP },    { "ipip", IP_PROTO_IPIP },    { "payload", IP_PROTO_PAYLOAD },    { "sctp", IP_PROTO_SCTP },    { "tcp", IP_PROTO_TCP },    { "tcpudp", IP_PROTO_TCP_OR_UDP },    { "transp", IP_PROTO_TRANSP },    { "udp", IP_PROTO_UDP }};static const StaticNameDB::Entry icmp_types[] = {    { "echo", ICMP_ECHO },    { "echo-reply", ICMP_ECHOREPLY },    { "inforeq", ICMP_IREQ },    { "inforeq-reply", ICMP_IREQREPLY },    { "maskreq", ICMP_MASKREQ },    { "maskreq-reply", ICMP_MASKREQREPLY },    { "parameterproblem", ICMP_PARAMPROB },    { "redirect", ICMP_REDIRECT },    { "routeradvert", ICMP_ROUTERADVERT },    { "routersolicit", ICMP_ROUTERSOLICIT },    { "sourcequench", ICMP_SOURCEQUENCH },    { "timeexceeded", ICMP_TIMXCEED },    { "timestamp", ICMP_TSTAMP },    { "timestamp-reply", ICMP_TSTAMPREPLY },    { "unreachable", ICMP_UNREACH },};static const StaticNameDB::Entry icmp_unreach_codes[] = {    { "filterprohibited", ICMP_UNREACH_FILTER_PROHIB },    { "host", ICMP_UNREACH_HOST },    { "hostprecedence", ICMP_UNREACH_HOST_PRECEDENCE },    { "hostprohibited", ICMP_UNREACH_HOST_PROHIB },    { "hostunknown", ICMP_UNREACH_HOST_UNKNOWN },    { "isolated", ICMP_UNREACH_ISOLATED },    { "needfrag", ICMP_UNREACH_NEEDFRAG },    { "net", ICMP_UNREACH_NET },    { "netprohibited", ICMP_UNREACH_NET_PROHIB },    { "netunknown", ICMP_UNREACH_NET_UNKNOWN },    { "port", ICMP_UNREACH_PORT },    { "precedencecutoff", ICMP_UNREACH_PRECEDENCE_CUTOFF },    { "protocol", ICMP_UNREACH_PROTOCOL },    { "srcroutefail", ICMP_UNREACH_SRCFAIL },    { "toshost", ICMP_UNREACH_TOSHOST },    { "tosnet", ICMP_UNREACH_TOSNET }};static const StaticNameDB::Entry icmp_redirect_codes[] = {    { "host", ICMP_REDIRECT_HOST },    { "net", ICMP_REDIRECT_NET },    { "toshost", ICMP_REDIRECT_TOSHOST },    { "tosnet", ICMP_REDIRECT_TOSNET }};static const StaticNameDB::Entry icmp_timxceed_codes[] = {    { "reassembly", ICMP_TIMXCEED_REASSEMBLY },    { "transit", ICMP_TIMXCEED_TRANSIT }};static const StaticNameDB::Entry icmp_paramprob_codes[] = {    { "erroratptr", ICMP_PARAMPROB_ERRATPTR },    { "length", ICMP_PARAMPROB_LENGTH },    { "missingopt", ICMP_PARAMPROB_OPTABSENT }};static const StaticNameDB::Entry known_ports[] = {    { "auth", 113 },    { "bootpc", 68 },    { "bootps", 67 },    { "chargen", 19 },    { "daytime", 13 },    { "discard", 9 },    { "dns", 53 },    { "domain", 53 },    { "echo", 7 },    { "finger", 79 },    { "ftp", 21 },    { "ftp-data", 20 },    { "https", 443 },    { "imap3", 220 },    { "imaps", 993 },    { "irc", 194 },    { "netbios-dgm", 138 },    { "netbios-ns", 137 },    { "netbios-ssn", 139 },    { "nntp", 119 },    { "ntp", 123 },    { "pop3", 110 },    { "pop3s", 995 },    { "rip", 520 },    { "route", 520 },    { "smtp", 25 },    { "snmp", 161 },    { "snmp-trap", 162 },    { "ssh", 22 },    { "sunrpc", 111 },    { "telnet", 23 },    { "tftp", 69 },    { "www", 80 }};namespace {#if CLICK_USERLEVEL && HAVE_NETDB_Hclass ServicesNameDB : public NameDB { public:    ServicesNameDB(uint32_t type, ServicesNameDB *other);    ~ServicesNameDB();    bool query(const String &name, void *value, size_t vsize);  private:    DynamicNameDB *_db;    bool _read_db;    ServicesNameDB *_next;    ServicesNameDB *_prev;    void read_services();};ServicesNameDB::ServicesNameDB(uint32_t type, ServicesNameDB *other)    : NameDB(type, String(), 4), _db(0), _read_db(false){    if (other) {	_next = other;	_prev = other->_prev;	other->_prev = _prev->_next = this;    } else	_next = _prev = this;}ServicesNameDB::~ServicesNameDB(){    _next->_prev = _prev;    _prev->_next = _next;    delete _db;}voidServicesNameDB::read_services(){#if 0    // On my Linux laptop, using the 'getprotoent()/getservent()' interface    // takes approximately 0.1s more than the hand-coded version below    // (which I coded before realizing 'getprotoent()/getservent()' exists).    if (type() == NameInfo::T_IP_PROTO) {	if (!_db)	    _db = new DynamicNameDB(type(), String(), 4);	while (struct protoent *p = getprotoent()) {	    uint32_t proto = p->p_proto;	    _db->define(p->p_name, &proto, 4);	    for (const char **a = (const char **) p->p_aliases; a && *a; a++)		_db->define(*a, &proto, 4);	}    } else	while (struct servent *s = getservent()) {	    uint32_t port = ntohs(s->s_port), ptype;	    if (!NameInfo::query_int(NameInfo::T_IP_PROTO, 0, s->s_proto, &ptype))		continue;	    ptype += NameInfo::T_IP_PORT;	    ServicesNameDB *db;	    for (db = _next; db->type() != ptype && db != this; db = db->_next)		/* nada */;	    if (db->type() != ptype)		continue;	    if (!db->_db)		db->_db = new DynamicNameDB(type(), String(), 4);	    db->_db->define(s->s_name, &port, 4);	    for (const char **a = (const char **) s->s_aliases; a && *a; a++)		db->_db->define(*a, &port, 4);	}#else    // Hand-coded version.    bool proto = (type() == NameInfo::T_IP_PROTO);    String text = file_string(proto ? _PATH_PROTOCOLS : _PATH_SERVICES);    if (!text)	return;    const char *s = text.begin(), *end = text.end();    while (s < end) {	const char *eol = s;	while (eol < end && *eol != '#' && *eol != '\r' && *eol != '\n')	    eol++;	// first word: main name	const char *bn, *en;	for (bn = s; bn < eol && isspace((unsigned char) *bn); bn++)	    /* nada */;	for (en = bn; en < eol && !isspace((unsigned char) *en); en++)	    /* nada */;	// second word: protocol type	const char *bt, *et;	uint32_t pnum = 0;	uint32_t ptype;	ServicesNameDB *db;	for (bt = en; bt < eol && isspace((unsigned char) *bt); bt++)	    /* nada */;	for (et = bt; et < eol && isdigit((unsigned char) *et) && pnum < 65536; et++)	    pnum = 10*pnum + *et - '0';	if (et == bt || pnum >= 65536 || et >= eol || (*et != '/' && *et != ','))	    goto skip_to_eol;	if (proto)	    ptype = NameInfo::T_IP_PROTO;	else {	    for (bt = et = et + 1; et < eol && !isspace((unsigned char) *et); et++)		/* nada */;	    if (!NameInfo::query_int(NameInfo::T_IP_PROTO, 0, text.substring(bt, et), &ptype))		goto skip_to_eol;	    ptype += NameInfo::T_IP_PORT;	    if (ptype != type())		goto skip_to_eol;	}	// find the database	for (db = _next; db->type() != ptype && db != this; db = db->_next)	    /* nada */;	if (db->type() != ptype)	    goto skip_to_eol;	// a series of assignments	if (!db->_db)	    db->_db = new DynamicNameDB(ptype, "", 4);	do {	    db->_db->define(text.substring(bn, en), &pnum, 4);	    for (bn = et; bn < eol && isspace((unsigned char) *bn); bn++)		/* nada */;	    for (en = bn; en < eol && !isspace((unsigned char) *en); en++)		/* nada */;	    et = en;	} while (bn != en);    skip_to_eol:	s = eol;	while (s < end && *s != '\r' && *s != '\n')	    s++;	while (s < end && (*s == '\r' || *s == '\n'))	    s++;    }#endif}boolServicesNameDB::query(const String &name, void *value, size_t vsize){    assert(vsize == 4);    // Check common case: integer    int32_t crap;    if (cp_integer(name, &crap))	return false;    if (!_read_db) {	read_services();	_read_db = true;    }    if (type() == NameInfo::T_IP_PROTO) {	if (!_db) {	    if (const struct protoent *proto = getprotobyname(name.c_str())) {		*reinterpret_cast<uint32_t*>(value) = proto->p_proto;		return true;	    }	} else if (_db->query(name, value, vsize))	    return true;    }    if (type() >= NameInfo::T_IP_PORT && type() < NameInfo::T_IP_PORT + 256) {	if (!_db) {	    int proto = type() - NameInfo::T_IP_PORT;	    const char *proto_name;	    if (proto == IP_PROTO_TCP)		proto_name = "tcp";	    else if (proto == IP_PROTO_UDP)		proto_name = "udp";	    else if (const struct protoent *pe = getprotobynumber(proto))		proto_name = pe->p_name;	    else		return false;	    if (const struct servent *srv = getservbyname(name.c_str(), proto_name)) {		*reinterpret_cast<uint32_t*>(value) = ntohs(srv->s_port);		return true;	    }	} else if (_db->query(name, value, vsize))	    return true;    }    return false;}#endif}static NameDB *dbs[13];voidIPNameInfo::static_initialize(){#if CLICK_USERLEVEL && HAVE_NETDB_H    dbs[0] = new ServicesNameDB(NameInfo::T_IP_PROTO, 0);#endif    dbs[1] = new StaticNameDB(NameInfo::T_IP_PROTO, String(), ip_protos, sizeof(ip_protos) / sizeof(ip_protos[0]));    dbs[2] = new StaticNameDB(NameInfo::T_ICMP_TYPE, String(), icmp_types, sizeof(icmp_types) / sizeof(icmp_types[0]));    dbs[3] = new StaticNameDB(NameInfo::T_ICMP_CODE + ICMP_UNREACH, String(), icmp_unreach_codes, sizeof(icmp_unreach_codes) / sizeof(icmp_unreach_codes[0]));    dbs[4] = new StaticNameDB(NameInfo::T_ICMP_CODE + ICMP_REDIRECT, String(), icmp_redirect_codes, sizeof(icmp_redirect_codes) / sizeof(icmp_redirect_codes[0]));    dbs[5] = new StaticNameDB(NameInfo::T_ICMP_CODE + ICMP_TIMXCEED, String(), icmp_timxceed_codes, sizeof(icmp_timxceed_codes) / sizeof(icmp_timxceed_codes[0]));    dbs[6] = new StaticNameDB(NameInfo::T_ICMP_CODE + ICMP_PARAMPROB, String(), icmp_paramprob_codes, sizeof(icmp_paramprob_codes) / sizeof(icmp_paramprob_codes[0]));#if CLICK_USERLEVEL && HAVE_NETDB_H    ServicesNameDB *portdb;    dbs[7] = portdb = new ServicesNameDB(NameInfo::T_TCP_PORT, 0);    dbs[8] = new ServicesNameDB(NameInfo::T_UDP_PORT, portdb);    dbs[9] = new ServicesNameDB(NameInfo::T_IP_PORT + IP_PROTO_SCTP, portdb);    dbs[10] = new ServicesNameDB(NameInfo::T_IP_PORT + IP_PROTO_DCCP, portdb);#endif    dbs[11] = new StaticNameDB(NameInfo::T_TCP_PORT, String(), known_ports, sizeof(known_ports) / sizeof(known_ports[0]));    dbs[12] = new StaticNameDB(NameInfo::T_UDP_PORT, String(), known_ports, sizeof(known_ports) / sizeof(known_ports[0]));    for (int i = 0; i < 13; i++)	if (dbs[i])	    NameInfo::installdb(dbs[i], 0);}voidIPNameInfo::static_cleanup(){    for (int i = 0; i < 13; i++)	if (dbs[i]) {	    delete dbs[i];	    dbs[i] = 0;	}}CLICK_ENDDECLSEXPORT_ELEMENT(IPNameInfo)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?