📄 anonipaddr.cc
字号:
// -*- c-basic-offset: 4 -*-/* * anonipaddr.{cc,hh} -- anonymize packet IP addresses * Eddie Kohler after Greg Minshall * * Copyright (c) 2001 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 "anonipaddr.hh"#include <click/standard/scheduleinfo.hh>#include <click/confparse.hh>#include <click/error.hh>#include <clicknet/ip.h>#include <clicknet/udp.h>#include <clicknet/icmp.h>#include <click/llrpc.h>#include <click/integers.hh> // for first_bit_set#ifdef CLICK_USERLEVEL# include <unistd.h># include <time.h>#endifCLICK_DECLSAnonymizeIPAddr::AnonymizeIPAddr() : Element(1, 0), _root(0), _free(0){}AnonymizeIPAddr::~AnonymizeIPAddr(){}AnonymizeIPAddr::Node *AnonymizeIPAddr::new_node_block(){ assert(!_free); int block_size = 1024; Node *block = new Node[block_size]; if (!block) return 0; _blocks.push_back(block); for (int i = 1; i < block_size - 1; i++) block[i].child[0] = &block[i+1]; block[block_size - 1].child[0] = 0; _free = &block[1]; return &block[0];}static uint32_trand32(){ return ((random() << 8) & 0xFFFF0000) | ((random() >> 12) & 0x0000FFFF);}voidAnonymizeIPAddr::notify_noutputs(int n){ set_noutputs(n <= 1 ? 1 : 2);}intAnonymizeIPAddr::configure(Vector<String> &conf, ErrorHandler *errh){ _preserve_class = 0; String preserve_8; bool seed = true; if (cp_va_parse(conf, this, errh, cpKeywords, "CLASS", cpInteger, "preserve class bits?", &_preserve_class, "PRESERVE_8", cpArgument, "list of /8s to preserve", &preserve_8, "SEED", cpBool, "seed random number generator?", &seed, cpEnd) < 0) return -1; // check CLASS value if (_preserve_class == 99) // allow 99 as synonym for 32 _preserve_class = 32; else if (_preserve_class > 32) errh->error("CLASS must be between 0 and 32"); // check preserve_8 if (preserve_8) { Vector<String> words; int what; cp_spacevec(preserve_8, words); for (int i = 0; i < words.size(); i++) if (cp_integer(words[i], &what) && what >= 0 && what < 256) _preserve_8.push_back(what); else return errh->error("bad PRESERVE_8 argument `%s', should be integer between 0 and 255", words[i].cc()); } // install seed if required if (seed) click_random_srandom(); return 0;}intAnonymizeIPAddr::initialize(ErrorHandler *errh){ if (!(_root = new_node())) return errh->error("out of memory!"); _root->input = 1; // use 1 instead of 0 b/c 0.0.0.0 is special _root->output = rand32(); _root->child[0] = _root->child[1] = 0; bool root_touched = false; // preserve classes if (_preserve_class > 0) { assert((0xFFFFFFFFU >> 1) == 0x7FFFFFFFU); uint32_t class_mask = ~(0xFFFFFFFFU >> _preserve_class); _root->input = class_mask; _root->output |= class_mask; root_touched = true; } // preserve requested /8s for (int i = 0; i < _preserve_8.size(); i++) { uint32_t addr = (_preserve_8[i] << 24); if (!root_touched) { _root->input = addr; _root->output = (_root->output & 0x00FFFFFF) | addr; root_touched = true; } else if (Node *n = find_node(addr)) n->output = (n->output & 0x00FFFFFF) | addr; else return errh->error("out of memory!"); } // prepare special nodes for 0.0.0.0 and 255.255.255.255 memset(&_special_nodes[0], 0, sizeof(_special_nodes)); _special_nodes[0].input = _special_nodes[0].output = 0; _special_nodes[1].input = _special_nodes[1].output = 0xFFFFFFFF; return 0;}voidAnonymizeIPAddr::cleanup(CleanupStage){ for (int i = 0; i < _blocks.size(); i++) delete[] _blocks[i]; _blocks.clear();}uint32_tAnonymizeIPAddr::make_output(uint32_t old_output, int swivel) const{ // -A50 anonymization if (swivel == 32) return old_output ^ 1; else { // bits up to swivel are unchanged; bit swivel is flipped uint32_t known_part = ((old_output >> (32 - swivel)) ^ 1) << (32 - swivel); // rest of bits are random return known_part | ((rand32() & 0x7FFFFFFF) >> swivel); }}AnonymizeIPAddr::Node *AnonymizeIPAddr::make_peer(uint32_t a, Node *n){ // watch out for special IP addresses, which never make it into the tree if (a == 0 || a == 0xFFFFFFFFU) return &_special_nodes[a & 1]; /* * become a peer * algo: create two nodes, the two peers. leave orig node as * the parent of the two new ones. */ Node *down[2]; if (!(down[0] = new_node())) return 0; if (!(down[1] = new_node())) { free_node(down[0]); return 0; } // swivel is first bit 'a' and 'old->input' differ int swivel = ffs_msb(a ^ n->input); // bitvalue is the value of that bit of 'a' int bitvalue = (a >> (32 - swivel)) & 1; down[bitvalue]->input = a; down[bitvalue]->output = make_output(n->output, swivel); down[bitvalue]->child[0] = down[bitvalue]->child[1] = 0; *down[1 - bitvalue] = *n; /* copy orig node down one level */ n->input = down[1]->input; /* NB: 1s to the right (0s to the left) */ n->output = down[1]->output; n->child[0] = down[0]; /* point to children */ n->child[1] = down[1]; return down[bitvalue];}AnonymizeIPAddr::Node *AnonymizeIPAddr::find_node(uint32_t a){ // straight outta tcpdpriv Node *n = _root; while (n) { if (n->input == a) return n; if (!n->child[0]) n = make_peer(a, n); else { // swivel is the first bit in which the two children differ int swivel = ffs_msb(n->child[0]->input ^ n->child[1]->input); if (ffs_msb(a ^ n->input) < swivel) // input differs earlier n = make_peer(a, n); else if (a & (1 << (32 - swivel))) n = n->child[1]; else n = n->child[0]; } } click_chatter("AnonymizeIPAddr: out of memory!"); return 0;}inline uint32_tAnonymizeIPAddr::anonymize_addr(uint32_t a){ if (Node *n = find_node(ntohl(a))) return htonl(n->output); else return 0;}voidAnonymizeIPAddr::handle_icmp(WritablePacket *q){ click_icmp *icmph = q->icmp_header(); if (icmph->icmp_type == ICMP_UNREACH || icmph->icmp_type == ICMP_TIMXCEED || icmph->icmp_type == ICMP_PARAMPROB || icmph->icmp_type == ICMP_SOURCEQUENCH || icmph->icmp_type == ICMP_REDIRECT) { // check length of embedded IP header click_ip *embedded_iph = reinterpret_cast<click_ip *>(icmph + 1); unsigned hlen = embedded_iph->ip_hl << 2; if (q->transport_length() < (int)(sizeof(click_icmp) + hlen + 8) || hlen < sizeof(click_ip)) return; uint32_t src = embedded_iph->ip_src.s_addr, dst = embedded_iph->ip_dst.s_addr; // incrementally update IP checksum according to RFC1624: // new_sum = ~(~old_sum + ~old_halfword + new_halfword) uint32_t icmp_sum = (~icmph->icmp_cksum & 0xFFFF) + (~src & 0xFFFF) + (~src >> 16) + (~dst & 0xFFFF) + (~dst >> 16); embedded_iph->ip_src.s_addr = src = anonymize_addr(src); embedded_iph->ip_dst.s_addr = dst = anonymize_addr(dst); icmp_sum += (src & 0xFFFF) + (src >> 16) + (dst & 0xFFFF) + (dst >> 16); icmp_sum = (icmp_sum & 0xFFFF) + (icmp_sum >> 16); icmph->icmp_cksum = ~(icmp_sum + (icmp_sum >> 16)); // XXX ICMP-in-ICMP? }}Packet *AnonymizeIPAddr::simple_action(Packet *p){ const click_ip *in_iph = p->ip_header(); if (!in_iph || in_iph->ip_v != 4) { checked_output_push(1, p); return 0; } else if (WritablePacket *q = p->uniqueify()) { click_ip *iph = q->ip_header(); uint32_t src = iph->ip_src.s_addr, dst = iph->ip_dst.s_addr; // incrementally update IP checksum according to RFC1624: // new_sum = ~(~old_sum + ~old_halfword + new_halfword) uint32_t sum = (~iph->ip_sum & 0xFFFF) + (~src & 0xFFFF) + (~src >> 16) + (~dst & 0xFFFF) + (~dst >> 16); iph->ip_src.s_addr = src = anonymize_addr(src); iph->ip_dst.s_addr = dst = anonymize_addr(dst); sum += (src & 0xFFFF) + (src >> 16) + (dst & 0xFFFF) + (dst >> 16); sum = (sum & 0xFFFF) + (sum >> 16); iph->ip_sum = ~(sum + (sum >> 16)); // check encapsulated headers for ICMP if (iph->ip_p == IP_PROTO_ICMP) handle_icmp(q); return q; } else return 0;}intAnonymizeIPAddr::llrpc(unsigned command, void *data){ if (command == CLICK_LLRPC_MAP_IPADDRESS) { // XXX should lock handler uint32_t *val = reinterpret_cast<uint32_t *>(data); *val = anonymize_addr(*val); return 0; } else return Element::llrpc(command, data);}CLICK_ENDDECLSEXPORT_ELEMENT(AnonymizeIPAddr)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -