├── .gitignore ├── Makefile ├── README.md ├── d3c.c ├── d4c.c ├── list.h ├── patricia.c ├── patricia.h ├── repgen.c ├── ssap_trie.h └── systemd ├── d4c.service └── etc-default-d4c /.gitignore: -------------------------------------------------------------------------------- 1 | d3c 2 | d4c 3 | repgen 4 | *.o 5 | core 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile 2 | 3 | 4 | CC = gcc -g -Wall 5 | PROGNAME = d3c d4c repgen 6 | INSTALL = /usr/bin/install 7 | INSTALLDST = /usr/local/bin 8 | 9 | all: $(PROGNAME) 10 | 11 | .c.o: 12 | $(CC) -c $< -o $@ 13 | 14 | d4c: patricia.o d4c.c 15 | $(CC) d4c.c -o $@ -lpthread patricia.o -DZEROCOPY 16 | 17 | d3c: patricia.o d3c.c 18 | $(CC) d3c.c -o $@ -lpthread patricia.o 19 | 20 | repgen: repgen.c 21 | $(CC) repgen.c -o repgen -lpthread 22 | 23 | install: d4c 24 | $(INSTALL) -m 744 -o root -g root d4c $(INSTALLDST)/d4c 25 | 26 | install-systemd: d4c install 27 | $(INSTALL) -m 644 -o root -g root \ 28 | systemd/etc-default-d4c /etc/default/d4c 29 | $(INSTALL) -m 644 -o root -g root \ 30 | systemd/d4c.service /etc/systemd/system/ 31 | 32 | clean: 33 | if [ -f $(INSTALLDST)/d4c ]; then \ 34 | rm -f $(INSTALLDST)/d4c; \ 35 | fi 36 | rm -f *.o 37 | rm -f $(PROGNAME) 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | D4C 2 | === 3 | 4 | DNS DDoS Defence and Countermeasure. 5 | 6 | d4c works as non-learning bridge and filter specified DNS packets that 7 | are suspected as DDoS traffic. 8 | 9 | 10 | % ./d4c 11 | Usage of d4c 12 | * required options. 13 | -r : Right interface name (netmap:ethX) 14 | -l : Left interface name (netmap:ethY) 15 | 16 | * DNS filtering options. 17 | -m : Filter suffix of DNS Query Name 18 | -d : Destination prefixes of filtered DNS responses 19 | -s : Source prefixes of NOT filtered DNS responses 20 | 21 | * misc. 22 | -q : Max number of threads for interface 23 | -e : Number of Rings of a vale port 24 | -f : Daemon mode 25 | -v : Verbose mode 26 | -h : Print this help 27 | 28 | 29 | 1. Drop DNS response packet from outer networks 30 | ----------------------------------------------- 31 | 32 | DNS DDoS traffic is generated by open resolvers around the world. 33 | When assuming that "correct DNS responses are sent from correct resolver 34 | servers", DNS responses from resolver servers in outer own networks are fully 35 | incorrect. 36 | 37 | So, d4c drop incorrect DNS response packets that match following conditions. 38 | 39 | - The packet is DNS response (QR flag is 1). 40 | - The packet is response from a resolver server (Authoritative flag is 0). 41 | - The destination address of packets is in the prefixes specified `-d` options. 42 | - The source address of packets is not in the prefixes specified `-s` options. 43 | 44 | -d option helps that you can apply this filter for specified hosts and networks. 45 | Moreover, -s option allows that using resolver servers in outer own network 46 | such as Google Public DNS. 47 | 48 | Example) 49 | 50 | sudo ./d4c -l netmap:p2p1 -r netmap:p2p2 -d 10.10.0.0/16 -d 172.16.0.0/16 -s 8.8.8.8/32 51 | 52 | The filter is applied for the networks 10.10.0.0/16 and 172.16.0.0/16, 53 | and DNS response packets from Google DNS are allowed. 54 | 55 | 56 | 2. Drop DNS query packet with specified QNAME 57 | --------------------------------------------- 58 | 59 | Query to generate DDoS traffic often contains striking QNAME. 60 | Dropping these query packets with striking QNAME helps reducing DDoS traffic. 61 | d4c provides a query filter function with QNAME _suffix_ match. 62 | -m options specify QNAME as suffix. 63 | 64 | Example) 65 | 66 | sudo ./d4c -l netmap:p2p1 -r netmap:p2p2 -m hogehoge.com -m hugahuga.com 67 | 68 | All queries for `.*hogehoge.com` and `.*hugahuga.com` are dropped. 69 | 70 | 71 | Filter rule 1 and 2 work independently. Specifying source/destination prefixes 72 | works only for rule 1. 73 | 74 | Compile 75 | ------- 76 | 77 | d4c is a netmap application. netmap.ko and netmap driver for interfaces used 78 | by d4c must be installed in advance. In order to compile, `netmap.h` and `netmap_user.h` must be installed on `/usr/include/net/`. 79 | -------------------------------------------------------------------------------- /d3c.c: -------------------------------------------------------------------------------- 1 | 2 | /* D3C: DNS DGA Domain and Countermeasure */ 3 | 4 | #include 5 | #include 6 | 7 | #define NETMAP_WITH_LIBS 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | 20 | #include "patricia.h" 21 | 22 | 23 | #define NM_BURST_MAX 1024 24 | 25 | #define ADDR4COPY(s, d) *(((u_int32_t *)(d))) = *(((u_int32_t *)(s))) 26 | #define ADDRCMP(s, d) (*(((u_int32_t *)(d))) == *(((u_int32_t *)(s)))) 27 | 28 | 29 | int verbose = 0; 30 | int vale_rings = 0; 31 | 32 | 33 | 34 | struct vnfapp { 35 | pthread_t tid; 36 | 37 | int rx_fd, tx_fd; 38 | int rx_q, tx_q; 39 | char * rx_if, * tx_if; 40 | struct netmap_ring * rx_ring, * tx_ring; 41 | 42 | void * data; 43 | }; 44 | 45 | 46 | 47 | 48 | struct d3c { 49 | void * match_table; /* binary tree for dns_match_match */ 50 | patricia_tree_t * dst_table; 51 | patricia_tree_t * src_table; 52 | }; 53 | 54 | struct d3c d3c; 55 | 56 | /* DNS related codes */ 57 | struct dns_hdr { 58 | u_int16_t id; 59 | u_int16_t flag; 60 | u_int16_t qn_count; 61 | u_int16_t an_count; 62 | u_int16_t ns_count; 63 | u_int16_t ar_count; 64 | 65 | char qname[0]; 66 | } __attribute__ ((__packed__)); 67 | #define DNS_FLAG_QR 0x8000 68 | #define DNS_FLAG_OP 0x1800 69 | #define DNS_FLAG_OP_STANDARD 0x0000 70 | #define DNS_FLAG_OP_INVERSE 0x0800 71 | #define DNS_FLAG_OP_STATUS 0x1000 72 | #define DNS_FLAG_AA 0x0400 73 | #define DNS_FLAG_TC 0x0200 74 | #define DNS_FLAG_RD 0x0100 75 | #define DNS_FLAG_RA 0x0080 76 | #define DNS_FLAG_RC 0x000F 77 | #define DNS_FLAG_RC_NOERR 0x0000 78 | #define DNS_FLAG_RC_FMTERR 0x0001 79 | #define DNS_FLAG_RC_SRVERR 0x0002 80 | #define DNS_FLAG_RC_NMERR 0x0003 81 | #define DNS_FLAG_RC_NOIMPL 0x0004 82 | #define DNS_FLAG_RC_DENIED 0x0005 83 | 84 | #define DNS_IS_QUERY(d) (!(ntohs ((d)->flag) & DNS_FLAG_QR)) 85 | #define DNS_IS_RESPONSE(d) ((ntohs ((d)->flag) & DNS_FLAG_QR)) 86 | #define DNS_IS_AUTHORITATIVE(d) (ntohs ((d)->flag) & DNS_FLAG_AA) 87 | 88 | 89 | /* DNS Queries related codes */ 90 | 91 | struct dns_qname_ftr { 92 | u_int16_t rep_type; 93 | u_int16_t rep_class; 94 | } __attribute__ ((__packed__)); 95 | #define DNS_REP_TYPE_A 1 96 | #define DNS_REP_TYPE_NS 2 97 | #define DNS_REP_TYPE_CNAME 5 98 | #define DNS_REP_TYPE_PTR 12 99 | #define DNS_REP_TYPE_MX 15 100 | #define DNS_REP_TYPE_AAAA 28 101 | #define DNS_REP_TYPE_ANY 255 102 | 103 | #define DNS_REP_CLASS_INTERNET 1 104 | 105 | 106 | /* DNS Filtering Query related codes */ 107 | 108 | #define DNS_MATCH_QUELY_LEN 256 109 | 110 | struct dns_match { 111 | char query[DNS_MATCH_QUELY_LEN]; 112 | int len; 113 | }; 114 | 115 | 116 | 117 | int 118 | dns_reassemble_domain (char * domain, char * buf, size_t buflen, size_t pktlen) 119 | { 120 | char * p; 121 | unsigned char s, n; 122 | 123 | p = domain; 124 | s = domain[0]; 125 | 126 | /* check, is domain compressed ? */ 127 | if ((s & 0xc0) == 0xc0) { 128 | return 0; 129 | } 130 | 131 | /* skip 1st number of chars */ 132 | p++; 133 | 134 | for (n = 0; n < buflen && n < pktlen; n++) { 135 | 136 | *(buf + n) = *(p + n); 137 | 138 | if (s == 0) { 139 | s = *(p + n); 140 | 141 | *(buf + n) = '.'; 142 | 143 | if (s == 0) { 144 | *(buf + n) = '\0'; 145 | break; 146 | } 147 | continue; 148 | } 149 | s--; 150 | } 151 | 152 | if (verbose) 153 | D ("Reassemble QNAME '%s'", buf); 154 | 155 | return n; 156 | } 157 | 158 | static int 159 | dns_match_compare (const void * pa, const void * pb) 160 | { 161 | int n, len; 162 | struct dns_match * ma, * mb; 163 | 164 | ma = (struct dns_match *) pa; 165 | mb = (struct dns_match *) pb; 166 | 167 | len = (ma->len > mb->len) ? mb->len : ma->len; 168 | 169 | for (n = 1; n <= len; n++) { 170 | if (*(ma->query + (ma->len - n)) == 171 | *(mb->query + (mb->len - n))) 172 | continue; 173 | 174 | if (*(ma->query + (ma->len - n)) > 175 | *(mb->query + (mb->len - n))) 176 | return 1; 177 | 178 | if (*(ma->query + (ma->len - n)) < 179 | *(mb->query + (mb->len - n))) 180 | return -1; 181 | } 182 | 183 | return 0; 184 | } 185 | 186 | int 187 | dns_add_match (void ** root, char * query) 188 | { 189 | void * p; 190 | struct dns_match * m; 191 | 192 | m = (struct dns_match *) malloc (sizeof (struct dns_match)); 193 | memset (m, 0, sizeof (struct dns_match)); 194 | 195 | strncpy (m->query, query, DNS_MATCH_QUELY_LEN); 196 | m->len = strlen (query); 197 | 198 | p = tsearch (m, root, dns_match_compare); 199 | if (p == NULL) { 200 | D ("failed to install dns match query '%s'", query); 201 | free (m); 202 | return 0; 203 | } 204 | 205 | return 1; 206 | } 207 | 208 | struct dns_match * 209 | dns_find_match (void ** root, struct dns_match * m) 210 | { 211 | void * p; 212 | 213 | p = tfind (m, root, dns_match_compare); 214 | 215 | if (!p) 216 | return NULL; 217 | 218 | return *((struct dns_match **) p); 219 | } 220 | 221 | int 222 | dns_check_match (struct dns_hdr * dns, size_t pktlen, void ** root) 223 | { 224 | int n; 225 | char * qn; 226 | struct dns_match m, * mr; 227 | 228 | qn = dns->qname; 229 | 230 | for (n = 0; n < ntohs (dns->qn_count); n++) { 231 | 232 | m.len = dns_reassemble_domain (qn, m.query, 233 | DNS_MATCH_QUELY_LEN, pktlen); 234 | 235 | mr = dns_find_match (root, &m); 236 | if (mr) { 237 | /* find ! drop ! */ 238 | if (verbose) { 239 | D ("Match %s is find for query '%s'", 240 | mr->query, m.query); 241 | } 242 | return 1; 243 | } 244 | 245 | /* check next qname. add len of qname and '.' */ 246 | qn = qn + m.len + 1 + sizeof (struct dns_qname_ftr); 247 | } 248 | 249 | return 0; 250 | } 251 | 252 | static void 253 | dns_walk_action (const void *nodep, const VISIT which, const int depth) 254 | { 255 | struct dns_match * m; 256 | 257 | switch (which) { 258 | case preorder: 259 | break; 260 | case postorder: 261 | m = *(struct dns_match **) nodep; 262 | printf ("%s\n", m->query); 263 | break; 264 | case endorder: 265 | break; 266 | case leaf: 267 | m = *(struct dns_match **) nodep; 268 | printf ("%s\n", m->query); 269 | break; 270 | } 271 | } 272 | 273 | 274 | /* prefix filter related codes for patricia tree */ 275 | 276 | static inline void 277 | dst2prefix (void * addr, u_int16_t len, prefix_t * prefix) 278 | { 279 | prefix->family = AF_INET; 280 | prefix->bitlen = len; 281 | prefix->ref_count = 1; 282 | 283 | ADDR4COPY (addr, &prefix->add); 284 | 285 | return; 286 | } 287 | 288 | static inline void * 289 | find_patricia_entry (patricia_tree_t * tree, void * addr, u_int16_t len) 290 | { 291 | prefix_t prefix; 292 | patricia_node_t * pn; 293 | 294 | dst2prefix (addr, len, &prefix); 295 | 296 | pn = patricia_search_best (tree, &prefix); 297 | 298 | if (pn) 299 | return pn->data; 300 | 301 | return NULL; 302 | } 303 | 304 | static inline void 305 | add_patricia_entry (patricia_tree_t * tree, void * addr, u_int16_t len, 306 | void * data) 307 | { 308 | prefix_t * prefix; 309 | patricia_node_t * pn; 310 | 311 | prefix = (prefix_t *) malloc (sizeof (prefix_t)); 312 | 313 | dst2prefix (addr, len, prefix); 314 | 315 | pn = patricia_lookup (tree, prefix); 316 | 317 | pn->data = data; 318 | 319 | return; 320 | } 321 | 322 | int 323 | split_prefixlen (char * str, void * prefix, int * len) 324 | { 325 | int n, l, c = 0; 326 | char * p, * args[2]; 327 | 328 | /* PREIFX/LEN */ 329 | 330 | p = str; 331 | args[c++] = str; 332 | l = strlen (str); 333 | 334 | for (n = 0; n < l; n++) { 335 | if (*(p + n) == '_' || *(p + n) == '/' || 336 | *(p + n) == ':' || *(p + n) == '-') { 337 | *(p + n) = '\0'; 338 | args[c++] = (p + n + 1); 339 | } 340 | } 341 | 342 | *len = atoi (args[1]); 343 | 344 | return inet_pton (AF_INET, args[0], prefix); 345 | } 346 | 347 | 348 | u_int 349 | move (struct vnfapp * va) 350 | { 351 | u_int burst, m, j, k; 352 | 353 | struct netmap_slot * rs, * ts; 354 | struct ether_header * eth; 355 | struct ip * ip; 356 | struct udphdr * udp; 357 | struct dns_hdr * dns; 358 | 359 | #define ZEROCOPY 360 | #ifdef ZEROCOPY 361 | u_int idx; 362 | #else 363 | char * spkt; 364 | char * dpkt; 365 | #endif 366 | 367 | j = va->rx_ring->cur; 368 | k = va->rx_ring->cur; 369 | burst = NM_BURST_MAX; 370 | 371 | m = nm_ring_space (va->rx_ring); 372 | if (m < burst) 373 | burst = m; 374 | 375 | m = nm_ring_space (va->tx_ring); 376 | if (m < burst) 377 | burst = m; 378 | 379 | m = burst; 380 | 381 | while (burst-- > 0) { 382 | 383 | 384 | rs = &va->rx_ring->slot[j]; 385 | ts = &va->tx_ring->slot[k]; 386 | 387 | if (ts->buf_idx < 2 || rs->buf_idx < 2) { 388 | D ("wrong index rx[%d] = %d -> tx[%d] = %d", 389 | j, rs->buf_idx, k, ts->buf_idx); 390 | sleep (2); 391 | } 392 | 393 | eth = (struct ether_header *) 394 | NETMAP_BUF (va->rx_ring, rs->buf_idx); 395 | ip = (struct ip *) (eth + 1); 396 | 397 | /* is DNS packet ? */ 398 | if (ip->ip_p != IPPROTO_UDP) 399 | goto packet_forward; 400 | 401 | udp = (struct udphdr *) (((char *) ip) + (ip->ip_hl * 4)); 402 | 403 | if (udp->source != htons (53)) 404 | goto packet_forward; 405 | 406 | 407 | dns = (struct dns_hdr *) (udp + 1); 408 | 409 | /* If it is QUERY and matched in domain black list */ 410 | if (DNS_IS_QUERY (dns) && 411 | dns_check_match (dns, rs->len, &d3c.match_table)) 412 | goto packet_drop; 413 | 414 | packet_forward: 415 | 416 | 417 | #ifdef ZEROCOPY 418 | idx = ts->buf_idx; 419 | ts->buf_idx = rs->buf_idx; 420 | rs->buf_idx = idx; 421 | ts->flags |= NS_BUF_CHANGED; 422 | rs->flags |= NS_BUF_CHANGED; 423 | ts->len = rs->len; 424 | #else 425 | spkt = NETMAP_BUF (va->rx_ring, rs->buf_idx); 426 | dpkt = NETMAP_BUF (va->tx_ring, ts->buf_idx); 427 | nm_pkt_copy (spkt, dpkt, rs->len); 428 | ts->len = rs->len; 429 | #endif 430 | 431 | packet_drop: 432 | j = nm_ring_next (va->rx_ring, j); 433 | k = nm_ring_next (va->tx_ring, k); 434 | } 435 | 436 | va->rx_ring->head = va->rx_ring->cur = j; 437 | va->tx_ring->head = va->tx_ring->cur = k; 438 | 439 | return m; 440 | } 441 | 442 | void * 443 | processing_thread (void * param) 444 | { 445 | struct pollfd x[1]; 446 | struct vnfapp * va = param; 447 | 448 | D ("rxfd=%d, txfd=%d, rxq=%d, txq=%d, rxif=%s, txif=%s, " 449 | "rxring=%p, txring=%p", 450 | va->rx_fd, va->tx_fd, va->rx_q, va->tx_q, va->rx_if, va->tx_if, 451 | va->rx_ring, va->tx_ring); 452 | 453 | pthread_detach (pthread_self ()); 454 | 455 | x[0].fd = va->rx_fd; 456 | x[0].events = POLLIN; 457 | 458 | while (1) { 459 | 460 | poll (x, 1, -1); 461 | 462 | ioctl (va->rx_fd, NIOCRXSYNC, va->rx_q); 463 | 464 | move (va); 465 | 466 | ioctl (va->tx_fd, NIOCTXSYNC, va->rx_q); 467 | } 468 | 469 | return NULL; 470 | } 471 | 472 | 473 | int 474 | nm_get_ring_num (char * ifname, int direct) 475 | { 476 | int fd; 477 | struct nmreq nmr; 478 | 479 | fd = open ("/dev/netmap", O_RDWR); 480 | if (fd < 0) { 481 | D ("Unable to open /dev/netmap"); 482 | perror ("open"); 483 | return -1; 484 | } 485 | 486 | memset (&nmr, 0, sizeof (nmr)); 487 | nmr.nr_version = NETMAP_API; 488 | strncpy (nmr.nr_name, ifname, IFNAMSIZ - 1); 489 | 490 | if (vale_rings && strncmp (ifname, "vale", 4) == 0) { 491 | nmr.nr_rx_rings = vale_rings; 492 | nmr.nr_tx_rings = vale_rings; 493 | } 494 | 495 | if (ioctl (fd, NIOCGINFO, &nmr)) { 496 | D ("unable to get interface info for %s", ifname); 497 | return -1; 498 | } 499 | 500 | close (fd); 501 | 502 | if (direct == 0) 503 | return nmr.nr_tx_rings; 504 | 505 | if (direct == 1) 506 | return nmr.nr_rx_rings; 507 | 508 | return -1; 509 | } 510 | #define nm_get_tx_ring_num(intf) nm_get_ring_num (intf, 0) 511 | #define nm_get_rx_ring_num(intf) nm_get_ring_num (intf, 1) 512 | 513 | int 514 | nm_ring (char * ifname, int q, struct netmap_ring ** ring, int x, int w) 515 | { 516 | int fd; 517 | char * mem; 518 | struct nmreq nmr; 519 | struct netmap_if * nifp; 520 | 521 | /* open netmap for ring */ 522 | 523 | fd = open ("/dev/netmap", O_RDWR); 524 | if (fd < 0) { 525 | D ("unable to open /dev/netmap"); 526 | return -1; 527 | } 528 | 529 | memset (&nmr, 0, sizeof (nmr)); 530 | strcpy (nmr.nr_name, ifname); 531 | nmr.nr_version = NETMAP_API; 532 | nmr.nr_ringid = q; 533 | 534 | if (w) 535 | nmr.nr_flags |= NR_REG_ONE_NIC; 536 | else 537 | nmr.nr_flags |= NR_REG_ALL_NIC; 538 | 539 | if (ioctl (fd, NIOCREGIF, &nmr) < 0) { 540 | D ("unable to register interface %s", ifname); 541 | return -1; 542 | } 543 | 544 | if (vale_rings && strncmp (ifname, "vale", 4) == 0) { 545 | nmr.nr_rx_rings = vale_rings; 546 | nmr.nr_tx_rings = vale_rings; 547 | } 548 | 549 | mem = mmap (NULL, nmr.nr_memsize, 550 | PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 551 | if (mem == MAP_FAILED) { 552 | D ("unable to mmap"); 553 | return -1; 554 | } 555 | 556 | nifp = NETMAP_IF (mem, nmr.nr_offset); 557 | 558 | if (x > 0) 559 | *ring = NETMAP_TXRING (nifp, q); 560 | else 561 | *ring = NETMAP_RXRING (nifp, q); 562 | 563 | return fd; 564 | } 565 | #define nm_hw_tx_ring(i, q, r) nm_ring (i, q, r, 1, NETMAP_HW_RING) 566 | #define nm_hw_rx_ring(i, q, r) nm_ring (i, q, r, 0, NETMAP_HW_RING) 567 | #define nm_sw_tx_ring(i, q, r) nm_ring (i, q, r, 1, NETMAP_SW_RING) 568 | #define nm_sw_rx_ring(i, q, r) nm_ring (i, q, r, 0, NETMAP_SW_RING) 569 | #define nm_vl_tx_ring(i, q, r) nm_ring (i, q, r, 1, 0) 570 | #define nm_vl_rx_ring(i, q, r) nm_ring (i, q, r, 0, 0) 571 | 572 | 573 | void 574 | usage (void) 575 | { 576 | printf ("Usage of d3c\n" 577 | "\t" "-r : Right interface name\n" 578 | "\t" "-l : Left interface name\n" 579 | "\t" "-q : Max number of threads for interface\n" 580 | "\t" "-d : Prefixes of filtered destination of DNS response\n" 581 | "\t" "-s : Prefixes that is NOT filtered DNS responses\n" 582 | "\t" "-e : Number of Rings of a vale port\n" 583 | "\t" "-m : Filter suffix of DNS Query Name\n" 584 | "\t" "-f : Daemon mode\n" 585 | "\t" "-v : Verbose mode\n" 586 | "\t" "-h : Print this help\n" 587 | ""); 588 | 589 | 590 | return; 591 | } 592 | 593 | int 594 | main (int argc, char ** argv) 595 | { 596 | struct in_addr prefix; 597 | int ret, q, rq, lq, n, len, ch, f_flag = 0; 598 | char * rif, * lif; 599 | 600 | q = 256; 601 | 602 | memset (&d3c, 0, sizeof (d3c)); 603 | d3c.dst_table = New_Patricia (32); 604 | d3c.src_table = New_Patricia (32); 605 | d3c.match_table = NULL; 606 | 607 | while ((ch = getopt (argc, argv, "r:l:q:e:d:s:m:fvh")) != -1) { 608 | switch (ch) { 609 | case 'r' : 610 | rif = optarg; 611 | break; 612 | case 'l' : 613 | lif = optarg; 614 | break; 615 | case 'q' : 616 | q = atoi (optarg); 617 | if (q < 1) { 618 | D ("Invalid -q argument."); 619 | return -1; 620 | } 621 | break; 622 | case 'e' : 623 | vale_rings = atoi (optarg); 624 | if (vale_rings > 4) { 625 | D ("Max of number of vale rings is 4."); 626 | return -1; 627 | } 628 | break; 629 | case 'd' : 630 | D ("Insert mitigated destination prefix %s", optarg); 631 | ret = split_prefixlen (optarg, &prefix, &len); 632 | if (ret < 0 || len < 0 || 32 < len) { 633 | D ("Invalid prefix %s", optarg); 634 | return -1; 635 | } 636 | 637 | /* main is dummy to avoid NULL */ 638 | add_patricia_entry (d3c.dst_table, &prefix, len, main); 639 | break; 640 | case 's' : 641 | D ("Insert unfiltered source prefix %s", optarg); 642 | ret = split_prefixlen (optarg, &prefix, &len); 643 | if (ret < 1 || len < 0 || 32 < len) { 644 | D ("Invalid prefix %s", optarg); 645 | return -1; 646 | } 647 | 648 | /* main is dummy to avoid NULL */ 649 | add_patricia_entry (d3c.src_table, &prefix, len, main); 650 | break; 651 | case 'm' : 652 | D ("Install match query %s", optarg); 653 | ret = dns_add_match (&d3c.match_table, optarg); 654 | if (!ret) { 655 | D ("failed to install match query %s", optarg); 656 | return -1; 657 | } 658 | break; 659 | case 'f' : 660 | f_flag = 1; 661 | break; 662 | case 'v' : 663 | verbose = 1; 664 | break; 665 | case 'h' : 666 | default : 667 | usage (); 668 | return -1; 669 | } 670 | } 671 | 672 | if (verbose) { 673 | D ("d3c.match_table walk start"); 674 | twalk (d3c.match_table, dns_walk_action); 675 | D ("d3c.match_table walk end"); 676 | } 677 | 678 | if (rif == NULL || lif == NULL) { 679 | usage (); 680 | return -1; 681 | } 682 | 683 | rq = nm_get_rx_ring_num (rif); 684 | lq = nm_get_rx_ring_num (lif); 685 | 686 | if (rq < 0 || lq < 0) { 687 | D ("failed to get number of rings"); 688 | return -1; 689 | } 690 | D ("Right rings is %d, Left rings is %d", rq, lq); 691 | 692 | if (f_flag) { 693 | daemon (0, 0); 694 | } 695 | 696 | 697 | rq = (rq < q) ? rq : q; 698 | lq = (lq < q) ? lq : q; 699 | 700 | 701 | /* Assign threads for each RX rings of Right interface */ 702 | for (n = 0; n < rq; n++) { 703 | struct vnfapp * va; 704 | va = (struct vnfapp *) malloc (sizeof (struct vnfapp)); 705 | memset (va, 0, sizeof (struct vnfapp)); 706 | 707 | va->rx_q = n; 708 | va->tx_q = n % lq; 709 | va->rx_if = rif; 710 | va->tx_if = lif; 711 | va->rx_fd = nm_vl_rx_ring (rif, va->rx_q, &va->rx_ring); 712 | va->tx_fd = nm_vl_tx_ring (lif, va->tx_q, &va->tx_ring); 713 | 714 | pthread_create (&va->tid, NULL, processing_thread, va); 715 | } 716 | 717 | /* Assign threads for each RX rings of Left interfaces */ 718 | for (n = 0; n < lq; n++) { 719 | struct vnfapp * va; 720 | va = (struct vnfapp *) malloc (sizeof (struct vnfapp)); 721 | memset (va, 0, sizeof (struct vnfapp)); 722 | 723 | va->rx_q = n; 724 | va->tx_q = n % rq; 725 | va->rx_if = lif; 726 | va->tx_if = rif; 727 | va->rx_fd = nm_vl_rx_ring (lif, va->rx_q, &va->rx_ring); 728 | va->tx_fd = nm_vl_tx_ring (rif, va->tx_q, &va->tx_ring); 729 | 730 | pthread_create (&va->tid, NULL, processing_thread, va); 731 | } 732 | 733 | 734 | 735 | while (1) { 736 | /* controlling module will be implemented here */ 737 | sleep (100); 738 | } 739 | 740 | return 0; 741 | } 742 | -------------------------------------------------------------------------------- /d4c.c: -------------------------------------------------------------------------------- 1 | 2 | /* D4C: Dirty Deeds Done Dirt Cheap */ 3 | 4 | #include 5 | #include 6 | 7 | #define NETMAP_WITH_LIBS 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | 20 | #include "patricia.h" 21 | #include "ssap_trie.h" 22 | 23 | #define NM_BURST_MAX 1024 24 | 25 | #define ADDR4COPY(s, d) *(((u_int32_t *)(d))) = *(((u_int32_t *)(s))) 26 | #define ADDRCMP(s, d) (*(((u_int32_t *)(d))) == *(((u_int32_t *)(s)))) 27 | 28 | #define THREAD_MAX 64 /* max number of threads (queuenum) */ 29 | #define MONITOR_PORT 5353 /* tcp port num for packet counter */ 30 | 31 | int verbose = 0; 32 | int vale_rings = 0; 33 | 34 | struct ether_vlan { 35 | __u8 ether_dhost[ETH_ALEN]; 36 | __u8 ether_shost[ETH_ALEN]; 37 | __u16 vlan_tpid; 38 | __u16 vlan_tci; 39 | __u16 ether_type; 40 | } __attribute__ ((__packed__)); 41 | 42 | 43 | struct vnfapp { 44 | pthread_t tid; 45 | 46 | /* netmap related */ 47 | int rx_fd, tx_fd; 48 | int rx_q, tx_q; 49 | char * rx_if, * tx_if; 50 | struct netmap_ring * rx_ring, * tx_ring; 51 | 52 | struct nm_desc * src, * dst; /* used for only single mode */ 53 | 54 | /* packet counters */ 55 | u_int32_t dropped_response_pkt; 56 | u_int32_t dropped_response_byte; 57 | u_int32_t dropped_query_pkt; 58 | u_int32_t dropped_query_byte; 59 | 60 | void * data; 61 | }; 62 | 63 | struct d4c { 64 | struct ssap_trie * match_table; /* ptree for dns_match */ 65 | patricia_tree_t * dst_table; 66 | patricia_tree_t * src_table; 67 | 68 | int vnfapps_num; 69 | struct vnfapp * vnfapps[THREAD_MAX]; 70 | 71 | int accept_sock; /* fd after accept */ 72 | int monitor_sock; /* tcp socket for packet counter */ 73 | int monitor_port; /* port number for tcp socket */ 74 | 75 | FILE * logfd; /* fd for logging dropped packet */ 76 | }; 77 | 78 | struct d4c d4c; 79 | 80 | #define GATHER_COUNTERS(val, n) \ 81 | do { \ 82 | val = 0; \ 83 | for ((n) = 0; (n) < d4c.vnfapps_num; (n)++) { \ 84 | val += d4c.vnfapps[(n)]->val; \ 85 | } \ 86 | } while (0) \ 87 | 88 | 89 | /* DNS related codes */ 90 | struct dns_hdr { 91 | u_int16_t id; 92 | u_int16_t flag; 93 | u_int16_t qn_count; 94 | u_int16_t an_count; 95 | u_int16_t ns_count; 96 | u_int16_t ar_count; 97 | 98 | char qname[0]; 99 | } __attribute__ ((__packed__)); 100 | #define DNS_FLAG_QR 0x8000 101 | #define DNS_FLAG_OP 0x1800 102 | #define DNS_FLAG_OP_STANDARD 0x0000 103 | #define DNS_FLAG_OP_INVERSE 0x0800 104 | #define DNS_FLAG_OP_STATUS 0x1000 105 | #define DNS_FLAG_AA 0x0400 106 | #define DNS_FLAG_TC 0x0200 107 | #define DNS_FLAG_RD 0x0100 108 | #define DNS_FLAG_RA 0x0080 109 | #define DNS_FLAG_RC 0x000F 110 | #define DNS_FLAG_RC_NOERR 0x0000 111 | #define DNS_FLAG_RC_FMTERR 0x0001 112 | #define DNS_FLAG_RC_SRVERR 0x0002 113 | #define DNS_FLAG_RC_NMERR 0x0003 114 | #define DNS_FLAG_RC_NOIMPL 0x0004 115 | #define DNS_FLAG_RC_DENIED 0x0005 116 | 117 | #define DNS_IS_QUERY(d) (!(ntohs ((d)->flag) & DNS_FLAG_QR)) 118 | #define DNS_IS_RESPONSE(d) ((ntohs ((d)->flag) & DNS_FLAG_QR)) 119 | #define DNS_IS_AUTHORITATIVE(d) (ntohs ((d)->flag) & DNS_FLAG_AA) 120 | 121 | 122 | /* DNS Queries related codes */ 123 | 124 | struct dns_qname_ftr { 125 | u_int16_t rep_type; 126 | u_int16_t rep_class; 127 | } __attribute__ ((__packed__)); 128 | #define DNS_REP_TYPE_A 1 129 | #define DNS_REP_TYPE_NS 2 130 | #define DNS_REP_TYPE_CNAME 5 131 | #define DNS_REP_TYPE_PTR 12 132 | #define DNS_REP_TYPE_MX 15 133 | #define DNS_REP_TYPE_AAAA 28 134 | #define DNS_REP_TYPE_ANY 255 135 | 136 | #define DNS_REP_CLASS_INTERNET 1 137 | 138 | 139 | /* DNS Filtering Query related codes */ 140 | 141 | #define DNS_MATCH_QUELY_LEN 256 142 | 143 | struct dns_match { 144 | char query[DNS_MATCH_QUELY_LEN]; 145 | int len; 146 | 147 | u_int32_t dropped_pkt; 148 | u_int32_t dropped_byte; 149 | }; 150 | 151 | 152 | 153 | int 154 | dns_reassemble_domain (char * domain, char * buf, size_t buflen, size_t pktlen) 155 | { 156 | char * p; 157 | unsigned char s, n; 158 | 159 | p = domain; 160 | s = domain[0]; 161 | 162 | /* check, is domain compressed ? */ 163 | if ((s & 0xc0) == 0xc0) { 164 | return 0; 165 | } 166 | 167 | /* skip 1st number of chars */ 168 | p++; 169 | 170 | for (n = 0; n < buflen && n < 255; n++) { 171 | 172 | *(buf + n) = *(p + n); 173 | 174 | if (s == 0) { 175 | s = *(p + n); 176 | if ((s & 0xc0) == 0xc0) { 177 | /* compressed. break... */ 178 | return 0; 179 | } 180 | *(buf + n) = '.'; 181 | 182 | if (s == 0) { 183 | *(buf + n) = '\0'; 184 | break; 185 | } 186 | continue; 187 | } 188 | s--; 189 | } 190 | 191 | if (n > 254) { 192 | D ("domain name length is over 255"); 193 | return 0; 194 | } 195 | 196 | if (verbose) 197 | D ("Reassemble QNAME '%s'", buf); 198 | 199 | return n; 200 | } 201 | 202 | 203 | int 204 | dns_add_match (struct ssap_trie * root, char * query) 205 | { 206 | struct dns_match * m; 207 | 208 | m = (struct dns_match *) malloc (sizeof (struct dns_match)); 209 | memset (m, 0, sizeof (struct dns_match)); 210 | 211 | strncpy (m->query, query, DNS_MATCH_QUELY_LEN); 212 | m->len = strlen (query); 213 | m->dropped_pkt = 0; 214 | m->dropped_byte = 0; 215 | 216 | ssap_trie_add (root, query, m); 217 | 218 | return 1; 219 | } 220 | 221 | struct dns_match * 222 | dns_find_match (struct ssap_trie * root, struct dns_match * m) 223 | { 224 | struct ssap_trie * trie; 225 | 226 | trie = ssap_trie_search (root, m->query); 227 | 228 | if (!trie) 229 | return NULL; 230 | 231 | return (struct dns_match *) trie->data; 232 | } 233 | 234 | struct dns_match * 235 | dns_check_match (struct dns_hdr * dns, size_t pktlen, struct ssap_trie * root) 236 | { 237 | char * qn; 238 | struct dns_match m, * mr; 239 | 240 | /* check only one qname */ 241 | 242 | qn = dns->qname; 243 | 244 | m.len = dns_reassemble_domain (qn, m.query, 245 | DNS_MATCH_QUELY_LEN, pktlen); 246 | 247 | mr = dns_find_match (root, &m); 248 | if (mr) { 249 | /* find ! drop ! */ 250 | if (verbose) { 251 | D ("Match %s is find for query '%s'", 252 | mr->query, m.query); 253 | } 254 | return mr; 255 | } 256 | 257 | return NULL; 258 | } 259 | 260 | static void 261 | dns_walk_action (void * data) 262 | { 263 | struct dns_match * m; 264 | 265 | m = (struct dns_match *) data; 266 | printf ("%s\n", m->query); 267 | } 268 | 269 | 270 | static void 271 | dns_walk_monitor (void * data) 272 | { 273 | char buf[1024]; 274 | struct dns_match * m = (struct dns_match *) data; 275 | 276 | memset (buf, 0, sizeof (buf)); 277 | 278 | snprintf (buf, sizeof (buf), 279 | "%s dropped_pkt %u dropped_byte %u\n", 280 | m->query, m->dropped_pkt, m->dropped_byte); 281 | 282 | write (d4c.accept_sock, buf, strlen (buf) + 1); 283 | } 284 | 285 | 286 | /* prefix filter related codes for patricia tree */ 287 | 288 | static inline void 289 | dst2prefix (void * addr, u_int16_t len, prefix_t * prefix) 290 | { 291 | prefix->family = AF_INET; 292 | prefix->bitlen = len; 293 | prefix->ref_count = 1; 294 | 295 | ADDR4COPY (addr, &prefix->add); 296 | 297 | return; 298 | } 299 | 300 | static inline void * 301 | find_patricia_entry (patricia_tree_t * tree, void * addr, u_int16_t len) 302 | { 303 | prefix_t prefix; 304 | patricia_node_t * pn; 305 | 306 | dst2prefix (addr, len, &prefix); 307 | 308 | pn = patricia_search_best (tree, &prefix); 309 | 310 | if (pn) 311 | return pn->data; 312 | 313 | return NULL; 314 | } 315 | 316 | static inline void 317 | add_patricia_entry (patricia_tree_t * tree, void * addr, u_int16_t len, 318 | void * data) 319 | { 320 | prefix_t * prefix; 321 | patricia_node_t * pn; 322 | 323 | prefix = (prefix_t *) malloc (sizeof (prefix_t)); 324 | 325 | dst2prefix (addr, len, prefix); 326 | 327 | pn = patricia_lookup (tree, prefix); 328 | 329 | pn->data = data; 330 | 331 | return; 332 | } 333 | 334 | int 335 | split_prefixlen (char * str, void * prefix, int * len) 336 | { 337 | int n, l, c = 0; 338 | char * p, * args[2] = { NULL, NULL }; 339 | 340 | /* PREIFX/LEN */ 341 | 342 | p = str; 343 | args[c++] = str; 344 | l = strlen (str); 345 | 346 | for (n = 0; n < l; n++) { 347 | if (*(p + n) == '_' || *(p + n) == '/' || 348 | *(p + n) == ':' || *(p + n) == '-') { 349 | *(p + n) = '\0'; 350 | args[c++] = (p + n + 1); 351 | } 352 | } 353 | 354 | if (!args[1]) 355 | *len = 32; 356 | else 357 | *len = atoi (args[1]); 358 | 359 | return inet_pton (AF_INET, args[0], prefix); 360 | } 361 | 362 | 363 | u_int 364 | move (struct vnfapp * va, struct netmap_ring * rx_ring, struct netmap_ring * tx_ring) 365 | { 366 | int n; 367 | char logbuf[256], addrbuf1[16], addrbuf2[16]; 368 | time_t timer; 369 | struct tm * tm; 370 | 371 | u_int burst, m, j, k; 372 | 373 | u_int16_t ether_type; 374 | struct ether_header * eth; 375 | struct ether_vlan * veth; 376 | struct ip * ip; 377 | struct udphdr * udp; 378 | struct dns_hdr * dns; 379 | struct dns_match * match; 380 | struct netmap_slot * rs, * ts; 381 | 382 | 383 | #ifdef ZEROCOPY 384 | u_int idx; 385 | #else 386 | char * spkt; 387 | char * dpkt; 388 | #endif 389 | 390 | j = rx_ring->cur; 391 | k = tx_ring->cur; 392 | burst = NM_BURST_MAX; 393 | 394 | m = nm_ring_space (rx_ring); 395 | if (m < burst) 396 | burst = m; 397 | 398 | m = nm_ring_space (tx_ring); 399 | if (m < burst) 400 | burst = m; 401 | 402 | m = burst; 403 | 404 | while (burst-- > 0) { 405 | 406 | rs = &rx_ring->slot[j]; 407 | ts = &tx_ring->slot[k]; 408 | 409 | if (ts->buf_idx < 2 || rs->buf_idx < 2) { 410 | D ("wrong index rx[%d] = %d -> tx[%d] = %d", 411 | j, rs->buf_idx, k, ts->buf_idx); 412 | sleep (2); 413 | } 414 | 415 | eth = (struct ether_header *) 416 | NETMAP_BUF (rx_ring, rs->buf_idx); 417 | ip = (struct ip *) (eth + 1); 418 | 419 | ether_type = eth->ether_type; 420 | 421 | if (ether_type == htons (ETHERTYPE_VLAN)) { 422 | veth = (struct ether_vlan *) 423 | NETMAP_BUF (rx_ring, rs->buf_idx); 424 | ether_type = veth->ether_type; 425 | ip = (struct ip *)(veth + 1); 426 | } 427 | 428 | if (ether_type != htons (ETHERTYPE_IP)) { 429 | /* XXX: IPv6 should be handled. */ 430 | goto packet_forward; 431 | } 432 | 433 | /* is DNS packet ? */ 434 | if (ip->ip_p != IPPROTO_UDP) 435 | goto packet_forward; 436 | 437 | udp = (struct udphdr *) (((char *) ip) + (ip->ip_hl * 4)); 438 | 439 | if (udp->source != htons (53) && udp->dest != htons (53)) 440 | goto packet_forward; 441 | 442 | dns = (struct dns_hdr *) (udp + 1); 443 | 444 | /* If dns packet is response and not authoritative, 445 | * the dns packet comes from a resolver server on 446 | * other AS !! It is DDoS packet !! Drop !! 447 | * (but, if it is from accepted source preifx, forwarded. 448 | */ 449 | 450 | if (DNS_IS_RESPONSE (dns) && 451 | !DNS_IS_AUTHORITATIVE (dns) && 452 | find_patricia_entry (d4c.dst_table, &ip->ip_dst, 32) && 453 | !find_patricia_entry (d4c.src_table, &ip->ip_src, 32)) { 454 | if (verbose) { 455 | D ("DDoS DNS Response from %s, Drop.", 456 | inet_ntoa (ip->ip_src)); 457 | } 458 | va->dropped_response_pkt++; 459 | va->dropped_response_byte += rs->len; 460 | goto packet_drop; 461 | } 462 | 463 | /* IF dns QNAME section is matched for installed tree, drop */ 464 | match = dns_check_match (dns, rs->len, d4c.match_table); 465 | //match = NULL; 466 | if (match) { 467 | va->dropped_query_pkt++; 468 | va->dropped_query_byte += rs->len; 469 | match->dropped_pkt++; 470 | match->dropped_byte += rs->len; 471 | 472 | if (d4c.logfd) { 473 | /* logging dropped packet */ 474 | 475 | time (&timer); 476 | tm = localtime (&timer); 477 | 478 | inet_ntop (AF_INET, &ip->ip_src, addrbuf1, 479 | sizeof (addrbuf1)); 480 | inet_ntop (AF_INET, &ip->ip_dst, addrbuf2, 481 | sizeof (addrbuf2)); 482 | snprintf (logbuf, sizeof (logbuf), 483 | "%d/%d/%d:%d:%d:%d %s->%s %s\n", 484 | tm->tm_year + 1900, 485 | tm->tm_mon + 1, 486 | tm->tm_mday, 487 | tm->tm_hour, 488 | tm->tm_min, 489 | tm->tm_sec, 490 | addrbuf1, addrbuf2, 491 | match->query); 492 | n = fputs (logbuf, d4c.logfd); 493 | if (n < 1) { 494 | D ("log write failed\n"); 495 | } 496 | } 497 | 498 | goto packet_drop; 499 | } 500 | 501 | packet_forward: 502 | 503 | 504 | #ifdef ZEROCOPY 505 | idx = ts->buf_idx; 506 | ts->buf_idx = rs->buf_idx; 507 | rs->buf_idx = idx; 508 | ts->flags |= NS_BUF_CHANGED; 509 | rs->flags |= NS_BUF_CHANGED; 510 | ts->len = rs->len; 511 | #else 512 | spkt = NETMAP_BUF (rx_ring, rs->buf_idx); 513 | dpkt = NETMAP_BUF (tx_ring, ts->buf_idx); 514 | nm_pkt_copy (spkt, dpkt, rs->len); 515 | ts->len = rs->len; 516 | #endif 517 | 518 | packet_drop: 519 | j = nm_ring_next (rx_ring, j); 520 | k = nm_ring_next (tx_ring, k); 521 | } 522 | 523 | rx_ring->head = rx_ring->cur = j; 524 | tx_ring->head = tx_ring->cur = k; 525 | 526 | return m; 527 | } 528 | 529 | u_int 530 | move2 (struct vnfapp * va) 531 | { 532 | return move (va, va->rx_ring, va->tx_ring); 533 | } 534 | 535 | void * 536 | processing_thread (void * param) 537 | { 538 | struct pollfd x[1]; 539 | struct vnfapp * va = param; 540 | 541 | D ("rxfd=%d, txfd=%d, rxq=%d, txq=%d, rxif=%s, txif=%s, " 542 | "rxring=%p, txring=%p", 543 | va->rx_fd, va->tx_fd, va->rx_q, va->tx_q, va->rx_if, va->tx_if, 544 | va->rx_ring, va->tx_ring); 545 | 546 | pthread_detach (pthread_self ()); 547 | 548 | x[0].fd = va->rx_fd; 549 | x[0].events = POLLIN; 550 | 551 | while (1) { 552 | 553 | poll (x, 1, -1); 554 | 555 | if (!nm_ring_empty (va->rx_ring)) { 556 | ioctl (va->rx_fd, NIOCRXSYNC, va->rx_q); 557 | move2 (va); 558 | ioctl (va->tx_fd, NIOCTXSYNC, va->tx_q); 559 | 560 | if (d4c.logfd) 561 | fflush (d4c.logfd); 562 | } 563 | } 564 | 565 | return NULL; 566 | } 567 | 568 | void * 569 | processing_single_thread (void * param) 570 | { 571 | struct vnfapp * va = (struct vnfapp *) param; 572 | struct nm_desc * src = va->src; 573 | struct nm_desc * dst = va->dst; 574 | struct pollfd x[1]; 575 | struct netmap_ring *txring, *rxring; 576 | u_int si, di; 577 | 578 | pthread_detach (pthread_self ()); 579 | 580 | x[0].fd = src->fd; 581 | x[0].events = POLLIN; 582 | 583 | while (1) { 584 | 585 | poll (x, 1, -1); 586 | 587 | si = src->first_rx_ring; 588 | di = dst->first_tx_ring; 589 | 590 | while (si <= src->last_rx_ring && di <= dst->last_tx_ring) { 591 | rxring = NETMAP_RXRING(src->nifp, si); 592 | txring = NETMAP_TXRING(dst->nifp, di); 593 | if (nm_ring_empty(rxring)) { 594 | si++; 595 | continue; 596 | } 597 | if (nm_ring_empty(txring)) { 598 | di++; 599 | continue; 600 | } 601 | move (va, rxring, txring); 602 | } 603 | } 604 | 605 | return NULL; 606 | } 607 | 608 | 609 | /* 610 | * packet counter thread. 611 | */ 612 | 613 | int 614 | tcp_server_socket (int port) 615 | { 616 | int sock, ret, val = 1; 617 | struct sockaddr_in saddr; 618 | 619 | sock = socket (AF_INET, SOCK_STREAM, 0); 620 | 621 | memset (&saddr, 0, sizeof (saddr)); 622 | saddr.sin_family = AF_INET; 623 | saddr.sin_port = htons (port); 624 | saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); 625 | 626 | ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof (val)); 627 | if (ret < 0) { 628 | perror ("monitor socket: failed to set SO_REUSEADDR"); 629 | return 0; 630 | } 631 | 632 | ret = bind (sock, (struct sockaddr *) &saddr, sizeof (saddr)); 633 | if (ret < 0) { 634 | perror ("monitor socket: bind failed"); 635 | return 0; 636 | } 637 | 638 | return sock; 639 | } 640 | 641 | void * 642 | processing_monitor_socket (void * param) 643 | { 644 | int n, fd; 645 | socklen_t len; 646 | char buf[1024]; 647 | struct sockaddr_in saddr; 648 | struct pollfd x[1]; 649 | 650 | u_int32_t dropped_response_pkt; 651 | u_int32_t dropped_response_byte; 652 | u_int32_t dropped_query_pkt; 653 | u_int32_t dropped_query_byte; 654 | 655 | d4c.monitor_sock = tcp_server_socket (d4c.monitor_port); 656 | if (!d4c.monitor_sock) { 657 | D ("faield to create monitor socket"); 658 | return NULL; 659 | } 660 | 661 | x[0].fd = d4c.monitor_sock; 662 | x[0].events = POLLIN | POLLERR; 663 | 664 | D ("start to listen monitor socket"); 665 | listen (d4c.monitor_sock, 1); 666 | 667 | while (1) { 668 | poll (x, 1, -1); 669 | 670 | if (x[0].revents & POLLIN) { 671 | /* accept new socket, write counters and close */ 672 | 673 | fd = accept (d4c.monitor_sock, 674 | (struct sockaddr *)&saddr, &len); 675 | d4c.accept_sock = fd; 676 | 677 | GATHER_COUNTERS (dropped_response_pkt, n); 678 | GATHER_COUNTERS (dropped_response_byte, n); 679 | GATHER_COUNTERS (dropped_query_pkt, n); 680 | GATHER_COUNTERS (dropped_query_byte, n); 681 | 682 | snprintf (buf, sizeof (buf), 683 | "dropped_response_pkt %u\n" 684 | "dropped_response_byte %u\n" 685 | "dropped_query_pkt %u\n" 686 | "dropped_query_byte %u\n", 687 | dropped_response_pkt, 688 | dropped_response_byte, 689 | dropped_query_pkt, 690 | dropped_query_byte); 691 | 692 | write (fd, buf, strlen (buf) + 1); 693 | 694 | ssap_trie_walk (d4c.match_table, dns_walk_monitor); 695 | 696 | close (fd); 697 | x[0].revents = 0; 698 | } 699 | } 700 | 701 | 702 | return NULL; 703 | } 704 | 705 | 706 | void 707 | usage (void) 708 | { 709 | printf ("Usage of d4c\n" 710 | "\t" " * required options.\n" 711 | "\t" "-r : Right interface name (netmap:ethX)\n" 712 | "\t" "-l : Left interface name (netmap:ethY)\n" 713 | "\n" 714 | "\t" " * DNS filtering options.\n" 715 | "\t" "-d : Destination prefixes of filtered DNS responses\n" 716 | "\t" "-s : Source prefixes of NOT filtered DNS responses\n" 717 | "\t" "-m : Filter suffix of DNS Query Name\n" 718 | "\n" 719 | "\t" " * misc.\n" 720 | "\t" "-q : Max number of threads for interface\n" 721 | "\t" "-e : Number of Rings of a vale port\n" 722 | "\t" "-p : TCP port number for packet counter (default 5353)\n" 723 | "\t" "-c : enable packet counter thread (default off)\n" 724 | "\t" "-f : Daemon mode\n" 725 | "\t" "-v : Verbose mode\n" 726 | "\t" "-h : Print this help\n" 727 | "\t" "-o : single thread mode\n" 728 | "\t" "-x [filename] : logging dropped packet\n" 729 | ""); 730 | 731 | 732 | return; 733 | } 734 | 735 | int 736 | main (int argc, char ** argv) 737 | { 738 | 739 | int ret, q, n, len, ch, f_flag = 0, c_flag = 0, o_flag = 0; 740 | char * rif, * lif; 741 | struct in_addr prefix; 742 | struct nm_desc * pr = NULL, * pl = NULL; 743 | 744 | q = 256; 745 | rif = NULL; 746 | lif = NULL; 747 | 748 | memset (&d4c, 0, sizeof (d4c)); 749 | d4c.dst_table = New_Patricia (32); 750 | d4c.src_table = New_Patricia (32); 751 | d4c.match_table = ssap_trie_new ('X'); 752 | d4c.vnfapps_num = 0; 753 | d4c.monitor_port = MONITOR_PORT; 754 | 755 | while ((ch = getopt (argc, argv, "r:l:q:e:d:s:m:p:x:cfvho")) != -1) { 756 | switch (ch) { 757 | case 'r' : 758 | rif = optarg; 759 | break; 760 | case 'l' : 761 | lif = optarg; 762 | break; 763 | case 'q' : 764 | q = atoi (optarg); 765 | if (q < 1) { 766 | D ("Invalid -q argument."); 767 | return -1; 768 | } 769 | break; 770 | case 'e' : 771 | vale_rings = atoi (optarg); 772 | if (vale_rings > 4) { 773 | D ("Max of number of vale rings is 4."); 774 | return -1; 775 | } 776 | break; 777 | case 'd' : 778 | D ("Insert mitigated destination prefix %s", optarg); 779 | ret = split_prefixlen (optarg, &prefix, &len); 780 | if (ret < 0 || len < 0 || 32 < len) { 781 | D ("Invalid prefix %s", optarg); 782 | return -1; 783 | } 784 | 785 | /* main is dummy to avoid NULL */ 786 | add_patricia_entry (d4c.dst_table, &prefix, len, main); 787 | break; 788 | case 's' : 789 | D ("Insert unfiltered source prefix %s", optarg); 790 | ret = split_prefixlen (optarg, &prefix, &len); 791 | if (ret < 1 || len < 0 || 32 < len) { 792 | D ("Invalid prefix %s", optarg); 793 | return -1; 794 | } 795 | 796 | /* main is dummy to avoid NULL */ 797 | add_patricia_entry (d4c.src_table, &prefix, len, main); 798 | break; 799 | case 'm' : 800 | D ("Install match query %s", optarg); 801 | ret = dns_add_match (d4c.match_table, optarg); 802 | if (!ret) { 803 | D ("failed to install match query %s", optarg); 804 | return -1; 805 | } 806 | break; 807 | case 'p' : 808 | d4c.monitor_port = atoi (optarg); 809 | D ("port number for packet counter is %d", 810 | d4c.monitor_port); 811 | break; 812 | case 'x' : 813 | d4c.logfd = fopen (optarg, "a"); 814 | if (d4c.logfd == NULL) { 815 | D ("failed to open %s", optarg); 816 | return -1; 817 | } 818 | break; 819 | case 'c' : 820 | c_flag = 1; 821 | break; 822 | case 'f' : 823 | f_flag = 1; 824 | break; 825 | case 'v' : 826 | verbose = 1; 827 | break; 828 | case 'o' : 829 | o_flag = 1; 830 | break; 831 | case 'h' : 832 | default : 833 | usage (); 834 | return -1; 835 | } 836 | } 837 | 838 | if (verbose) { 839 | D ("d4c.match_table walk start"); 840 | ssap_trie_walk (d4c.match_table, dns_walk_action); 841 | D ("d4c.match_table walk end"); 842 | } 843 | 844 | if (rif == NULL || lif == NULL) { 845 | D ("left anr right interfaces must be specified."); 846 | usage (); 847 | return -1; 848 | } 849 | 850 | pr = nm_open (rif, NULL, 0, NULL); 851 | if (!pr) { 852 | D ("can not open %s", rif); 853 | return -1; 854 | } 855 | 856 | pl = nm_open (lif, NULL, 0, NULL); 857 | if (!pr) { 858 | D ("can not open %s", lif); 859 | return -1; 860 | } 861 | 862 | if (o_flag) { 863 | /* single thread mode */ 864 | struct vnfapp * va_r_l; 865 | va_r_l = (struct vnfapp *) malloc (sizeof (struct vnfapp)); 866 | memset (va_r_l, 0, sizeof (struct vnfapp)); 867 | va_r_l->src = pr; 868 | va_r_l->dst = pl; 869 | d4c.vnfapps[d4c.vnfapps_num++] = va_r_l; 870 | pthread_create (&va_r_l->tid, NULL, processing_single_thread, va_r_l); 871 | 872 | struct vnfapp * va_l_r; 873 | va_l_r = (struct vnfapp *) malloc (sizeof (struct vnfapp)); 874 | memset (va_l_r, 0, sizeof (struct vnfapp)); 875 | va_l_r->src = pl; 876 | va_l_r->dst = pr; 877 | d4c.vnfapps[d4c.vnfapps_num++] = va_l_r; 878 | pthread_create (&va_l_r->tid, NULL, processing_single_thread, va_l_r); 879 | } else { 880 | 881 | /* Assign threads for each RX rings of Right interface */ 882 | for (n = pl->first_rx_ring; n <= pl->last_rx_ring; n++) { 883 | struct vnfapp * va; 884 | va = (struct vnfapp *) malloc (sizeof (struct vnfapp)); 885 | memset (va, 0, sizeof (struct vnfapp)); 886 | va->rx_q = n; 887 | va->tx_q = n % (pr->last_tx_ring - pr->first_tx_ring + 1); 888 | va->rx_if = rif; 889 | va->tx_if = lif; 890 | va->rx_fd = pl->fd; 891 | va->tx_fd = pr->fd; 892 | va->rx_ring = NETMAP_RXRING (pl->nifp, va->rx_q); 893 | va->tx_ring = NETMAP_TXRING (pr->nifp, va->tx_q); 894 | 895 | d4c.vnfapps[d4c.vnfapps_num++] = va; 896 | 897 | pthread_create (&va->tid, NULL, processing_thread, va); 898 | } 899 | 900 | /* Assign threads for each RX rings of Left interfaces */ 901 | for (n = pr->first_rx_ring; n <= pr->last_rx_ring; n++) { 902 | struct vnfapp * va; 903 | va = (struct vnfapp *) malloc (sizeof (struct vnfapp)); 904 | memset (va, 0, sizeof (struct vnfapp)); 905 | va->rx_q = n; 906 | va->tx_q = n % (pl->last_tx_ring - pl->first_tx_ring + 1); 907 | va->rx_if = lif; 908 | va->tx_if = rif; 909 | va->rx_fd = pr->fd; 910 | va->tx_fd = pl->fd; 911 | va->rx_ring = NETMAP_RXRING (pr->nifp, va->rx_q); 912 | va->tx_ring = NETMAP_TXRING (pl->nifp, va->tx_q); 913 | 914 | d4c.vnfapps[d4c.vnfapps_num++] = va; 915 | 916 | pthread_create (&va->tid, NULL, processing_thread, va); 917 | } 918 | } 919 | 920 | if (f_flag) { 921 | daemon (0, 0); 922 | } 923 | 924 | if (c_flag) { 925 | processing_monitor_socket (NULL); 926 | } else { 927 | while (1) sleep (100); 928 | } 929 | 930 | return 0; 931 | } 932 | -------------------------------------------------------------------------------- /list.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIST_H 2 | #define __LIST_H 3 | 4 | #define offset_of(type,member) ((size_t)&(((type*)0)->member)) 5 | 6 | //#define LIST_POISON1 0xdeaddead 7 | //#define LIST_POISON2 0xbedeadbe 8 | #define LIST_POISON1 0 9 | #define LIST_POISON2 0 10 | 11 | #define container_of(pointer,type,member)\ 12 | (type*)((char*)(pointer) - offset_of(type,member)) 13 | 14 | struct list_head { 15 | struct list_head *prev,*next; 16 | }; 17 | 18 | static inline void INIT_LIST_HEAD(struct list_head *list) 19 | { 20 | list->next = list; 21 | list->prev = list; 22 | } 23 | 24 | static inline void __list_add(struct list_head *new, 25 | struct list_head *prev, 26 | struct list_head *next) 27 | { 28 | next->prev = new; 29 | new->next = next; 30 | new->prev = prev; 31 | prev->next = new; 32 | } 33 | static inline void list_add(struct list_head *new, struct list_head *head) 34 | { 35 | __list_add(new, head, head->next); 36 | } 37 | 38 | static inline void list_add_tail(struct list_head *new, struct list_head *head) 39 | { 40 | __list_add(new, head->prev, head); 41 | } 42 | 43 | static inline void __list_del(struct list_head * prev, struct list_head * next) 44 | { 45 | next->prev = prev; 46 | prev->next = next; 47 | } 48 | 49 | static inline void list_del(struct list_head *entry) 50 | { 51 | __list_del(entry->prev, entry->next); 52 | entry->next = LIST_POISON1; 53 | entry->prev = LIST_POISON2; 54 | } 55 | 56 | static inline void list_move(struct list_head *list, struct list_head *head) 57 | { 58 | __list_del(list->prev, list->next); 59 | list_add(list, head); 60 | } 61 | 62 | static inline void list_move_tail(struct list_head *list, 63 | struct list_head *head) 64 | { 65 | __list_del(list->prev, list->next); 66 | list_add_tail(list, head); 67 | } 68 | 69 | static inline int list_empty(const struct list_head *head) 70 | { 71 | return head->next == head; 72 | } 73 | 74 | static inline void list_del_init(struct list_head *entry) 75 | { 76 | __list_del(entry->prev, entry->next); 77 | INIT_LIST_HEAD(entry); 78 | } 79 | 80 | #define list_for_each_safe(pos, n, head) \ 81 | for (pos = (head)->next, n = pos->next; pos != (head); \ 82 | pos = n, n = pos->next) 83 | 84 | #define list_entry(ptr, type, member) \ 85 | container_of(ptr, type, member) 86 | 87 | #endif /*__LIST_H*/ -------------------------------------------------------------------------------- /patricia.c: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: patricia.c,v 1.7 2005/12/07 20:46:41 dplonka Exp $ 3 | * Dave Plonka 4 | * 5 | * This product includes software developed by the University of Michigan, 6 | * Merit Network, Inc., and their contributors. 7 | * 8 | * This file had been called "radix.c" in the MRT sources. 9 | * 10 | * I renamed it to "patricia.c" since it's not an implementation of a general 11 | * radix trie. Also I pulled in various requirements from "prefix.c" and 12 | * "demo.c" so that it could be used as a standalone API. 13 | * 14 | * 15 | * Bunch of mods from David Meyer (dmm613@gmail.com) to make 16 | * this deal with IPv6 in a more friendly fashion 17 | * 18 | * 19 | */ 20 | 21 | #include /* assert */ 22 | #include /* isdigit */ 23 | #include /* errno */ 24 | #include /* sin */ 25 | #include /* NULL */ 26 | #include /* sprintf, fprintf, stderr */ 27 | #include /* free, atol, calloc */ 28 | #include /* memcpy, strchr, strlen */ 29 | #include /* BSD: for inet_addr */ 30 | #include /* BSD, Linux: for inet_addr */ 31 | #include 32 | #include /* BSD, Linux: for inet_addr */ 33 | #include /* BSD, Linux, Solaris: for inet_addr */ 34 | 35 | #include "patricia.h" 36 | 37 | #define Delete free 38 | 39 | /* { from prefix.c */ 40 | 41 | /* prefix_tochar 42 | * convert prefix information to bytes 43 | */ 44 | u_char *prefix_tochar (prefix_t * prefix) 45 | { 46 | if (prefix == NULL) 47 | return (NULL); 48 | return ((u_char *) & prefix->add.sin); 49 | } 50 | 51 | int comp_with_mask (void *addr, void *dest, u_int mask) 52 | { 53 | 54 | if ( /* mask/8 == 0 || */ memcmp (addr, dest, mask / 8) == 0) { 55 | int n = mask / 8; 56 | int m = ((-1) << (8 - (mask % 8))); 57 | 58 | if (mask % 8 == 0 || (((u_char *)addr)[n] & m) == (((u_char *)dest)[n] & m)) 59 | return (1); 60 | } 61 | return (0); 62 | } 63 | 64 | 65 | /* this allows imcomplete prefix */ 66 | int my_inet_pton (int af, const char *src, void *dst) 67 | { 68 | if (af == AF_INET) { 69 | int i, c, val; 70 | u_char xp[sizeof(struct in_addr)] = {0, 0, 0, 0}; 71 | 72 | for (i = 0; ; i++) { 73 | c = *src++; 74 | if (!isdigit (c)) 75 | return (-1); 76 | val = 0; 77 | do { 78 | val = val * 10 + c - '0'; 79 | if (val > 255) 80 | return (0); 81 | c = *src++; 82 | } while (c && isdigit (c)); 83 | xp[i] = val; 84 | if (c == '\0') 85 | break; 86 | if (c != '.') 87 | return (0); 88 | if (i >= 3) 89 | return (0); 90 | } 91 | memcpy (dst, xp, sizeof(struct in_addr)); 92 | return (1); 93 | } else if (af == AF_INET6) { 94 | return (inet_pton (af, src, dst)); 95 | } else { 96 | return -1; 97 | } 98 | } 99 | 100 | #define PATRICIA_MAX_THREADS 16 101 | 102 | /* 103 | * convert prefix information to ascii string with length 104 | * thread safe and (almost) re-entrant implementation 105 | */ 106 | char *prefix_toa2x (prefix_t *prefix, char *buff, int with_len) 107 | { 108 | if (prefix == NULL) 109 | return ("(Null)"); 110 | 111 | assert (prefix->ref_count >= 0); 112 | 113 | if (buff == NULL) { 114 | 115 | struct buffer { 116 | char buffs[PATRICIA_MAX_THREADS][48+5]; 117 | u_int i; 118 | } *buffp; 119 | 120 | # if 0 121 | THREAD_SPECIFIC_DATA (struct buffer, buffp, 1); 122 | # else 123 | { /* for scope only */ 124 | static struct buffer local_buff; 125 | buffp = &local_buff; 126 | } 127 | # endif 128 | if (buffp == NULL) { 129 | /* XXX should we report an error? */ 130 | return (NULL); 131 | } 132 | 133 | buff = buffp->buffs[buffp->i++%PATRICIA_MAX_THREADS]; 134 | } 135 | if (prefix->family == AF_INET) { 136 | u_char *a; 137 | assert (prefix->bitlen <= sizeof(struct in_addr) * 8); 138 | a = prefix_touchar (prefix); 139 | if (with_len) { 140 | sprintf (buff, "%d.%d.%d.%d/%d", a[0], a[1], a[2], a[3], 141 | prefix->bitlen); 142 | } 143 | else { 144 | sprintf (buff, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]); 145 | } 146 | return (buff); 147 | } 148 | else if (prefix->family == AF_INET6) { 149 | char *r; 150 | r = (char *) inet_ntop (AF_INET6, &(prefix->add.sin6), buff, 48 /* a guess value */ ); 151 | 152 | if (r && with_len) { 153 | assert (prefix->bitlen <= sizeof(struct in6_addr) * 8); 154 | sprintf (buff + strlen (buff), "/%d", prefix->bitlen); 155 | } 156 | return (buff); 157 | } 158 | else 159 | return (NULL); 160 | } 161 | 162 | /* prefix_toa2 163 | * convert prefix information to ascii string 164 | */ 165 | char *prefix_toa2 (prefix_t *prefix, char *buff) 166 | { 167 | return (prefix_toa2x (prefix, buff, 0)); 168 | } 169 | 170 | /* prefix_toa 171 | */ 172 | char *prefix_toa (prefix_t * prefix) 173 | { 174 | return (prefix_toa2 (prefix, (char *) NULL)); 175 | } 176 | 177 | prefix_t *New_Prefix2 (int family, void *dest, int bitlen, prefix_t *prefix) 178 | { 179 | int dynamic_allocated = 0; 180 | int default_bitlen = 0; 181 | 182 | if (prefix == NULL) { 183 | /* prefix = calloc(1, sizeof (prefix_t)); */ 184 | if ((prefix = (prefix_t *) malloc(sizeof(prefix_t))) == NULL) { 185 | syslog(LOG_DAEMON, "New_Prefix2: can't allocate new prefix"); 186 | return(0); 187 | } 188 | memset(prefix, 0, sizeof (prefix_t)); 189 | dynamic_allocated++; 190 | } 191 | 192 | 193 | switch(family) { 194 | case AF_INET: 195 | default_bitlen = sizeof(struct in_addr) * 8; 196 | memcpy (&prefix->add.sin, dest, sizeof(struct in_addr)); 197 | break; 198 | case AF_INET6: 199 | default_bitlen = sizeof(struct in6_addr) * 8; 200 | memcpy (&prefix->add.sin6, dest, sizeof(struct in6_addr)); 201 | break; 202 | default: 203 | free(prefix); 204 | return (NULL); 205 | } 206 | 207 | prefix->bitlen = (bitlen >= 0)? bitlen: default_bitlen; 208 | prefix->family = family; 209 | prefix->ref_count = 0; 210 | if (dynamic_allocated) { 211 | prefix->ref_count++; 212 | } 213 | return (prefix); 214 | } 215 | 216 | prefix_t *New_Prefix (int family, void *dest, int bitlen) 217 | { 218 | return (New_Prefix2 (family, dest, bitlen, NULL)); 219 | } 220 | 221 | /* ascii2prefix 222 | */ 223 | prefix_t * ascii2prefix (int family, char *string) 224 | { 225 | u_long bitlen = 0; 226 | u_long maxbitlen = 0; 227 | char *cp = NULL; 228 | int result = 0; 229 | struct in_addr sin; 230 | struct in6_addr sin6; 231 | char save[MAXLINE]; 232 | 233 | if (!string) 234 | return (NULL); 235 | 236 | switch(family) { /* set up maxbitlen */ 237 | case AF_INET: 238 | maxbitlen = sizeof(struct in_addr) * 8; 239 | break; 240 | case AF_INET6: 241 | maxbitlen = sizeof(struct in6_addr) * 8; 242 | break; 243 | default: 244 | fprintf(stderr, "unknown AFI (%d)\n", family); 245 | return(0); 246 | } 247 | 248 | if ((cp = strchr (string, '/')) != NULL) { 249 | bitlen = atol (cp + 1); 250 | /* *cp = '\0'; */ 251 | /* copy the string to save. Avoid destroying the string */ 252 | assert (cp - string < MAXLINE); 253 | memcpy (save, string, cp - string); 254 | save[cp - string] = '\0'; 255 | string = save; 256 | if (bitlen > maxbitlen) 257 | bitlen = maxbitlen; 258 | } 259 | else { 260 | bitlen = maxbitlen; 261 | } 262 | 263 | /* 264 | * now do the conversion 265 | */ 266 | 267 | switch(family) { 268 | case AF_INET: 269 | if ((result = my_inet_pton (AF_INET, string, &sin)) <= 0) 270 | return (NULL); 271 | return (New_Prefix (AF_INET, &sin, bitlen)); 272 | case AF_INET6: 273 | if ((result = inet_pton (AF_INET6, string, &sin6)) <= 0) 274 | return (NULL); 275 | return (New_Prefix (AF_INET6, &sin6, bitlen)); 276 | default: 277 | return (NULL); 278 | } 279 | } 280 | 281 | prefix_t *Ref_Prefix (prefix_t * prefix) 282 | { 283 | if (prefix == NULL) 284 | return (NULL); 285 | if (prefix->ref_count == 0) { 286 | /* make a copy in case of a static prefix */ 287 | return (New_Prefix2 (prefix->family, &prefix->add, prefix->bitlen, NULL)); 288 | } 289 | prefix->ref_count++; 290 | /* fprintf(stderr, "[A %s, %d]\n", prefix_toa (prefix), prefix->ref_count); */ 291 | return (prefix); 292 | } 293 | 294 | void Deref_Prefix (prefix_t * prefix) 295 | { 296 | if (prefix == NULL) 297 | return; 298 | /* for secure programming, raise an assert. no static prefix can call this */ 299 | assert (prefix->ref_count > 0); 300 | 301 | prefix->ref_count--; 302 | assert (prefix->ref_count >= 0); 303 | if (prefix->ref_count <= 0) { 304 | Delete (prefix); 305 | return; 306 | } 307 | } 308 | 309 | /* } */ 310 | 311 | /* #define PATRICIA_DEBUG 1 */ 312 | 313 | static int num_active_patricia = 0; 314 | 315 | /* these routines support continuous mask only */ 316 | 317 | patricia_tree_t * 318 | New_Patricia (int maxbits) 319 | { 320 | patricia_tree_t *patricia = calloc(1, sizeof *patricia); 321 | 322 | patricia->maxbits = maxbits; 323 | patricia->head = NULL; 324 | patricia->num_active_node = 0; 325 | assert (maxbits <= PATRICIA_MAXBITS); /* XXX */ 326 | num_active_patricia++; 327 | return (patricia); 328 | } 329 | 330 | 331 | /* 332 | * if func is supplied, it will be called as func(node->data) 333 | * before deleting the node 334 | */ 335 | 336 | void 337 | Clear_Patricia (patricia_tree_t *patricia, void_fn_t func) 338 | { 339 | assert (patricia); 340 | if (patricia->head) { 341 | 342 | patricia_node_t *Xstack[PATRICIA_MAXBITS+1]; 343 | patricia_node_t **Xsp = Xstack; 344 | patricia_node_t *Xrn = patricia->head; 345 | 346 | while (Xrn) { 347 | patricia_node_t *l = Xrn->l; 348 | patricia_node_t *r = Xrn->r; 349 | 350 | if (Xrn->prefix) { 351 | Deref_Prefix (Xrn->prefix); 352 | if (Xrn->data && func) 353 | func (Xrn->data); 354 | } 355 | else { 356 | assert (Xrn->data == NULL); 357 | } 358 | Delete (Xrn); 359 | patricia->num_active_node--; 360 | 361 | if (l) { 362 | if (r) { 363 | *Xsp++ = r; 364 | } 365 | Xrn = l; 366 | } else if (r) { 367 | Xrn = r; 368 | } else if (Xsp != Xstack) { 369 | Xrn = *(--Xsp); 370 | } else { 371 | Xrn = NULL; 372 | } 373 | } 374 | } 375 | assert (patricia->num_active_node == 0); 376 | /* Delete (patricia); */ 377 | } 378 | 379 | 380 | void 381 | Destroy_Patricia (patricia_tree_t *patricia, void_fn_t func) 382 | { 383 | Clear_Patricia (patricia, func); 384 | Delete (patricia); 385 | num_active_patricia--; 386 | } 387 | 388 | 389 | /* 390 | * if func is supplied, it will be called as func(node->prefix, node->data) 391 | */ 392 | 393 | void 394 | patricia_process (patricia_tree_t *patricia, void_fn_t func) 395 | { 396 | patricia_node_t *node; 397 | assert (func); 398 | 399 | PATRICIA_WALK (patricia->head, node) { 400 | func (node->prefix, node->data); 401 | } PATRICIA_WALK_END; 402 | } 403 | 404 | size_t 405 | patricia_walk_inorder(patricia_node_t *node, void_fn_t func) 406 | { 407 | size_t n = 0; 408 | assert(func); 409 | 410 | if (node->l) { 411 | n += patricia_walk_inorder(node->l, func); 412 | } 413 | 414 | if (node->prefix) { 415 | func(node->prefix, node->data); 416 | n++; 417 | } 418 | 419 | if (node->r) { 420 | n += patricia_walk_inorder(node->r, func); 421 | } 422 | 423 | return n; 424 | } 425 | 426 | 427 | patricia_node_t * 428 | patricia_search_exact (patricia_tree_t *patricia, prefix_t *prefix) 429 | { 430 | patricia_node_t *node; 431 | u_char *addr; 432 | u_int bitlen; 433 | 434 | assert (patricia); 435 | assert (prefix); 436 | assert (prefix->bitlen <= patricia->maxbits); 437 | 438 | if (patricia->head == NULL) 439 | return (NULL); 440 | 441 | node = patricia->head; 442 | addr = prefix_touchar (prefix); 443 | bitlen = prefix->bitlen; 444 | 445 | while (node->bit < bitlen) { 446 | 447 | if (BIT_TEST (addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) { 448 | #ifdef PATRICIA_DEBUG 449 | if (node->prefix) 450 | fprintf (stderr, "patricia_search_exact: take right %s/%d\n", 451 | prefix_toa (node->prefix), node->prefix->bitlen); 452 | else 453 | fprintf (stderr, "patricia_search_exact: take right at %u\n", 454 | node->bit); 455 | #endif /* PATRICIA_DEBUG */ 456 | node = node->r; 457 | } 458 | else { 459 | #ifdef PATRICIA_DEBUG 460 | if (node->prefix) 461 | fprintf (stderr, "patricia_search_exact: take left %s/%d\n", 462 | prefix_toa (node->prefix), node->prefix->bitlen); 463 | else 464 | fprintf (stderr, "patricia_search_exact: take left at %u\n", 465 | node->bit); 466 | #endif /* PATRICIA_DEBUG */ 467 | node = node->l; 468 | } 469 | 470 | if (node == NULL) 471 | return (NULL); 472 | } 473 | 474 | #ifdef PATRICIA_DEBUG 475 | if (node->prefix) 476 | fprintf (stderr, "patricia_search_exact: stop at %s/%d\n", 477 | prefix_toa (node->prefix), node->prefix->bitlen); 478 | else 479 | fprintf (stderr, "patricia_search_exact: stop at %u\n", node->bit); 480 | #endif /* PATRICIA_DEBUG */ 481 | if (node->bit > bitlen || node->prefix == NULL) 482 | return (NULL); 483 | assert (node->bit == bitlen); 484 | assert (node->bit == node->prefix->bitlen); 485 | if (comp_with_mask (prefix_tochar (node->prefix), prefix_tochar (prefix), 486 | bitlen)) { 487 | #ifdef PATRICIA_DEBUG 488 | fprintf (stderr, "patricia_search_exact: found %s/%d\n", 489 | prefix_toa (node->prefix), node->prefix->bitlen); 490 | #endif /* PATRICIA_DEBUG */ 491 | return (node); 492 | } 493 | return (NULL); 494 | } 495 | 496 | 497 | /* if inclusive != 0, "best" may be the given prefix itself */ 498 | patricia_node_t * 499 | patricia_search_best2 (patricia_tree_t *patricia, prefix_t *prefix, int inclusive) 500 | { 501 | patricia_node_t *node; 502 | patricia_node_t *stack[PATRICIA_MAXBITS + 1]; 503 | u_char *addr; 504 | u_int bitlen; 505 | int cnt = 0; 506 | 507 | assert (patricia); 508 | assert (prefix); 509 | assert (prefix->bitlen <= patricia->maxbits); 510 | 511 | if (patricia->head == NULL) 512 | return (NULL); 513 | 514 | node = patricia->head; 515 | addr = prefix_touchar (prefix); 516 | bitlen = prefix->bitlen; 517 | 518 | while (node->bit < bitlen) { 519 | 520 | if (node->prefix) { 521 | #ifdef PATRICIA_DEBUG 522 | fprintf (stderr, "patricia_search_best: push %s/%d\n", 523 | prefix_toa (node->prefix), node->prefix->bitlen); 524 | #endif /* PATRICIA_DEBUG */ 525 | stack[cnt++] = node; 526 | } 527 | 528 | if (BIT_TEST (addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) { 529 | #ifdef PATRICIA_DEBUG 530 | if (node->prefix) 531 | fprintf (stderr, "patricia_search_best: take right %s/%d\n", 532 | prefix_toa (node->prefix), node->prefix->bitlen); 533 | else 534 | fprintf (stderr, "patricia_search_best: take right at %u\n", 535 | node->bit); 536 | #endif /* PATRICIA_DEBUG */ 537 | node = node->r; 538 | } 539 | else { 540 | #ifdef PATRICIA_DEBUG 541 | if (node->prefix) 542 | fprintf (stderr, "patricia_search_best: take left %s/%d\n", 543 | prefix_toa (node->prefix), node->prefix->bitlen); 544 | else 545 | fprintf (stderr, "patricia_search_best: take left at %u\n", 546 | node->bit); 547 | #endif /* PATRICIA_DEBUG */ 548 | node = node->l; 549 | } 550 | 551 | if (node == NULL) 552 | break; 553 | } 554 | 555 | if (inclusive && node && node->prefix) 556 | stack[cnt++] = node; 557 | 558 | #ifdef PATRICIA_DEBUG 559 | if (node == NULL) 560 | fprintf (stderr, "patricia_search_best: stop at null\n"); 561 | else if (node->prefix) 562 | fprintf (stderr, "patricia_search_best: stop at %s/%d\n", 563 | prefix_toa (node->prefix), node->prefix->bitlen); 564 | else 565 | fprintf (stderr, "patricia_search_best: stop at %u\n", node->bit); 566 | #endif /* PATRICIA_DEBUG */ 567 | 568 | if (cnt <= 0) 569 | return (NULL); 570 | 571 | while (--cnt >= 0) { 572 | node = stack[cnt]; 573 | #ifdef PATRICIA_DEBUG 574 | fprintf (stderr, "patricia_search_best: pop %s/%d\n", 575 | prefix_toa (node->prefix), node->prefix->bitlen); 576 | #endif /* PATRICIA_DEBUG */ 577 | if (comp_with_mask (prefix_tochar (node->prefix), 578 | prefix_tochar (prefix), 579 | node->prefix->bitlen) && node->prefix->bitlen <= bitlen) { 580 | #ifdef PATRICIA_DEBUG 581 | fprintf (stderr, "patricia_search_best: found %s/%d\n", 582 | prefix_toa (node->prefix), node->prefix->bitlen); 583 | #endif /* PATRICIA_DEBUG */ 584 | return (node); 585 | } 586 | } 587 | return (NULL); 588 | } 589 | 590 | 591 | patricia_node_t * 592 | patricia_search_best (patricia_tree_t *patricia, prefix_t *prefix) 593 | { 594 | return (patricia_search_best2 (patricia, prefix, 1)); 595 | } 596 | 597 | 598 | patricia_node_t * 599 | patricia_lookup (patricia_tree_t *patricia, prefix_t *prefix) 600 | { 601 | patricia_node_t *node, *new_node, *parent, *glue; 602 | u_char *addr, *test_addr; 603 | u_int bitlen, check_bit, differ_bit; 604 | int i, j, r; 605 | 606 | assert (patricia); 607 | assert (prefix); 608 | assert (prefix->bitlen <= patricia->maxbits); 609 | 610 | if (patricia->head == NULL) { 611 | node = calloc(1, sizeof *node); 612 | node->bit = prefix->bitlen; 613 | node->prefix = Ref_Prefix (prefix); 614 | node->parent = NULL; 615 | node->l = node->r = NULL; 616 | node->data = NULL; 617 | patricia->head = node; 618 | #ifdef PATRICIA_DEBUG 619 | fprintf (stderr, "patricia_lookup: new_node #0 %s/%d (head)\n", 620 | prefix_toa (prefix), prefix->bitlen); 621 | #endif /* PATRICIA_DEBUG */ 622 | patricia->num_active_node++; 623 | return (node); 624 | } 625 | 626 | addr = prefix_touchar (prefix); 627 | bitlen = prefix->bitlen; 628 | node = patricia->head; 629 | 630 | while (node->bit < bitlen || node->prefix == NULL) { 631 | 632 | if (node->bit < patricia->maxbits && 633 | BIT_TEST (addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) { 634 | if (node->r == NULL) 635 | break; 636 | #ifdef PATRICIA_DEBUG 637 | if (node->prefix) 638 | fprintf (stderr, "patricia_lookup: take right %s/%d\n", 639 | prefix_toa (node->prefix), node->prefix->bitlen); 640 | else 641 | fprintf (stderr, "patricia_lookup: take right at %u\n", node->bit); 642 | #endif /* PATRICIA_DEBUG */ 643 | node = node->r; 644 | } 645 | else { 646 | if (node->l == NULL) 647 | break; 648 | #ifdef PATRICIA_DEBUG 649 | if (node->prefix) 650 | fprintf (stderr, "patricia_lookup: take left %s/%d\n", 651 | prefix_toa (node->prefix), node->prefix->bitlen); 652 | else 653 | fprintf (stderr, "patricia_lookup: take left at %u\n", node->bit); 654 | #endif /* PATRICIA_DEBUG */ 655 | node = node->l; 656 | } 657 | 658 | assert (node); 659 | } 660 | 661 | assert (node->prefix); 662 | #ifdef PATRICIA_DEBUG 663 | fprintf (stderr, "patricia_lookup: stop at %s/%d\n", 664 | prefix_toa (node->prefix), node->prefix->bitlen); 665 | #endif /* PATRICIA_DEBUG */ 666 | 667 | test_addr = prefix_touchar (node->prefix); 668 | /* find the first bit different */ 669 | check_bit = (node->bit < bitlen)? node->bit: bitlen; 670 | differ_bit = 0; 671 | for (i = 0; i*8 < check_bit; i++) { 672 | if ((r = (addr[i] ^ test_addr[i])) == 0) { 673 | differ_bit = (i + 1) * 8; 674 | continue; 675 | } 676 | /* I know the better way, but for now */ 677 | for (j = 0; j < 8; j++) { 678 | if (BIT_TEST (r, (0x80 >> j))) 679 | break; 680 | } 681 | /* must be found */ 682 | assert (j < 8); 683 | differ_bit = i * 8 + j; 684 | break; 685 | } 686 | if (differ_bit > check_bit) 687 | differ_bit = check_bit; 688 | #ifdef PATRICIA_DEBUG 689 | fprintf (stderr, "patricia_lookup: differ_bit %d\n", differ_bit); 690 | #endif /* PATRICIA_DEBUG */ 691 | 692 | parent = node->parent; 693 | while (parent && parent->bit >= differ_bit) { 694 | node = parent; 695 | parent = node->parent; 696 | #ifdef PATRICIA_DEBUG 697 | if (node->prefix) 698 | fprintf (stderr, "patricia_lookup: up to %s/%d\n", 699 | prefix_toa (node->prefix), node->prefix->bitlen); 700 | else 701 | fprintf (stderr, "patricia_lookup: up to %u\n", node->bit); 702 | #endif /* PATRICIA_DEBUG */ 703 | } 704 | 705 | if (differ_bit == bitlen && node->bit == bitlen) { 706 | if (node->prefix) { 707 | #ifdef PATRICIA_DEBUG 708 | fprintf (stderr, "patricia_lookup: found %s/%d\n", 709 | prefix_toa (node->prefix), node->prefix->bitlen); 710 | #endif /* PATRICIA_DEBUG */ 711 | return (node); 712 | } 713 | node->prefix = Ref_Prefix (prefix); 714 | #ifdef PATRICIA_DEBUG 715 | fprintf (stderr, "patricia_lookup: new node #1 %s/%d (glue mod)\n", 716 | prefix_toa (prefix), prefix->bitlen); 717 | #endif /* PATRICIA_DEBUG */ 718 | assert (node->data == NULL); 719 | return (node); 720 | } 721 | 722 | new_node = calloc(1, sizeof *new_node); 723 | new_node->bit = prefix->bitlen; 724 | new_node->prefix = Ref_Prefix (prefix); 725 | new_node->parent = NULL; 726 | new_node->l = new_node->r = NULL; 727 | new_node->data = NULL; 728 | patricia->num_active_node++; 729 | 730 | if (node->bit == differ_bit) { 731 | new_node->parent = node; 732 | if (node->bit < patricia->maxbits && 733 | BIT_TEST (addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) { 734 | assert (node->r == NULL); 735 | node->r = new_node; 736 | } 737 | else { 738 | assert (node->l == NULL); 739 | node->l = new_node; 740 | } 741 | #ifdef PATRICIA_DEBUG 742 | fprintf (stderr, "patricia_lookup: new_node #2 %s/%d (child)\n", 743 | prefix_toa (prefix), prefix->bitlen); 744 | #endif /* PATRICIA_DEBUG */ 745 | return (new_node); 746 | } 747 | 748 | if (bitlen == differ_bit) { 749 | if (bitlen < patricia->maxbits && 750 | BIT_TEST (test_addr[bitlen >> 3], 0x80 >> (bitlen & 0x07))) { 751 | new_node->r = node; 752 | } 753 | else { 754 | new_node->l = node; 755 | } 756 | new_node->parent = node->parent; 757 | if (node->parent == NULL) { 758 | assert (patricia->head == node); 759 | patricia->head = new_node; 760 | } 761 | else if (node->parent->r == node) { 762 | node->parent->r = new_node; 763 | } 764 | else { 765 | node->parent->l = new_node; 766 | } 767 | node->parent = new_node; 768 | #ifdef PATRICIA_DEBUG 769 | fprintf (stderr, "patricia_lookup: new_node #3 %s/%d (parent)\n", 770 | prefix_toa (prefix), prefix->bitlen); 771 | #endif /* PATRICIA_DEBUG */ 772 | } 773 | else { 774 | glue = calloc(1, sizeof *glue); 775 | glue->bit = differ_bit; 776 | glue->prefix = NULL; 777 | glue->parent = node->parent; 778 | glue->data = NULL; 779 | patricia->num_active_node++; 780 | if (differ_bit < patricia->maxbits && 781 | BIT_TEST (addr[differ_bit >> 3], 0x80 >> (differ_bit & 0x07))) { 782 | glue->r = new_node; 783 | glue->l = node; 784 | } 785 | else { 786 | glue->r = node; 787 | glue->l = new_node; 788 | } 789 | new_node->parent = glue; 790 | 791 | if (node->parent == NULL) { 792 | assert (patricia->head == node); 793 | patricia->head = glue; 794 | } 795 | else if (node->parent->r == node) { 796 | node->parent->r = glue; 797 | } 798 | else { 799 | node->parent->l = glue; 800 | } 801 | node->parent = glue; 802 | #ifdef PATRICIA_DEBUG 803 | fprintf (stderr, "patricia_lookup: new_node #4 %s/%d (glue+node)\n", 804 | prefix_toa (prefix), prefix->bitlen); 805 | #endif /* PATRICIA_DEBUG */ 806 | } 807 | return (new_node); 808 | } 809 | 810 | 811 | void 812 | patricia_remove (patricia_tree_t *patricia, patricia_node_t *node) 813 | { 814 | patricia_node_t *parent, *child; 815 | 816 | assert (patricia); 817 | assert (node); 818 | 819 | if (node->r && node->l) { 820 | #ifdef PATRICIA_DEBUG 821 | fprintf (stderr, "patricia_remove: #0 %s/%d (r & l)\n", 822 | prefix_toa (node->prefix), node->prefix->bitlen); 823 | #endif /* PATRICIA_DEBUG */ 824 | 825 | /* this might be a placeholder node -- have to check and make sure 826 | * there is a prefix aossciated with it ! */ 827 | if (node->prefix != NULL) 828 | Deref_Prefix (node->prefix); 829 | node->prefix = NULL; 830 | /* Also I needed to clear data pointer -- masaki */ 831 | node->data = NULL; 832 | return; 833 | } 834 | 835 | if (node->r == NULL && node->l == NULL) { 836 | #ifdef PATRICIA_DEBUG 837 | fprintf (stderr, "patricia_remove: #1 %s/%d (!r & !l)\n", 838 | prefix_toa (node->prefix), node->prefix->bitlen); 839 | #endif /* PATRICIA_DEBUG */ 840 | parent = node->parent; 841 | Deref_Prefix (node->prefix); 842 | Delete (node); 843 | patricia->num_active_node--; 844 | 845 | if (parent == NULL) { 846 | assert (patricia->head == node); 847 | patricia->head = NULL; 848 | return; 849 | } 850 | 851 | if (parent->r == node) { 852 | parent->r = NULL; 853 | child = parent->l; 854 | } 855 | else { 856 | assert (parent->l == node); 857 | parent->l = NULL; 858 | child = parent->r; 859 | } 860 | 861 | if (parent->prefix) 862 | return; 863 | 864 | /* we need to remove parent too */ 865 | 866 | if (parent->parent == NULL) { 867 | assert (patricia->head == parent); 868 | patricia->head = child; 869 | } 870 | else if (parent->parent->r == parent) { 871 | parent->parent->r = child; 872 | } 873 | else { 874 | assert (parent->parent->l == parent); 875 | parent->parent->l = child; 876 | } 877 | child->parent = parent->parent; 878 | Delete (parent); 879 | patricia->num_active_node--; 880 | return; 881 | } 882 | 883 | #ifdef PATRICIA_DEBUG 884 | fprintf (stderr, "patricia_remove: #2 %s/%d (r ^ l)\n", 885 | prefix_toa (node->prefix), node->prefix->bitlen); 886 | #endif /* PATRICIA_DEBUG */ 887 | if (node->r) { 888 | child = node->r; 889 | } 890 | else { 891 | assert (node->l); 892 | child = node->l; 893 | } 894 | parent = node->parent; 895 | child->parent = parent; 896 | 897 | Deref_Prefix (node->prefix); 898 | Delete (node); 899 | patricia->num_active_node--; 900 | 901 | if (parent == NULL) { 902 | assert (patricia->head == node); 903 | patricia->head = child; 904 | return; 905 | } 906 | 907 | if (parent->r == node) { 908 | parent->r = child; 909 | } 910 | else { 911 | assert (parent->l == node); 912 | parent->l = child; 913 | } 914 | } 915 | 916 | 917 | patricia_node_t * make_and_lookup (patricia_tree_t *tree, int afi, char *string) 918 | { 919 | prefix_t *prefix; 920 | patricia_node_t *node; 921 | 922 | prefix = ascii2prefix (afi, string); 923 | 924 | #if (DEBUG > 3) 925 | printf ("make_and_lookup: %s/%d\n", prefix_toa (prefix), prefix->bitlen); 926 | #endif 927 | 928 | node = patricia_lookup (tree, prefix); 929 | Deref_Prefix (prefix); 930 | return (node); 931 | } 932 | 933 | patricia_node_t * 934 | try_search_exact (patricia_tree_t *tree, int afi, char *string) 935 | { 936 | prefix_t *prefix; 937 | patricia_node_t *node; 938 | 939 | prefix = ascii2prefix (afi, string); 940 | node = patricia_search_exact (tree, prefix); 941 | 942 | #ifdef DEBUG 943 | if (node) 944 | printf ("try_search_exact: %s/%d found\n", 945 | prefix_toa (node->prefix), node->prefix->bitlen); 946 | else 947 | printf ("try_search_exact: not found\n"); 948 | #endif 949 | 950 | Deref_Prefix (prefix); 951 | return (node); 952 | } 953 | 954 | void 955 | lookup_then_remove (patricia_tree_t *tree, int afi, char *string) 956 | { 957 | patricia_node_t *node; 958 | 959 | if ((node = try_search_exact (tree, afi, string)) != NULL) 960 | patricia_remove (tree, node); 961 | } 962 | 963 | patricia_node_t * 964 | try_search_best (patricia_tree_t *tree, int afi, char *string) 965 | { 966 | prefix_t *prefix; 967 | patricia_node_t *node; 968 | 969 | prefix = ascii2prefix (afi, string); 970 | printf ("try_search_best: %s/%d\n", prefix_toa (prefix), prefix->bitlen); 971 | if ((node = patricia_search_best (tree, prefix)) == NULL) 972 | printf ("try_search_best: not found\n"); 973 | else 974 | printf ("try_search_best: %s/%d found\n", 975 | prefix_toa (node->prefix), node->prefix->bitlen); 976 | Deref_Prefix (prefix); 977 | return (node); /* was return(prefix) ...why? */ 978 | 979 | } 980 | 981 | /* } */ 982 | -------------------------------------------------------------------------------- /patricia.h: -------------------------------------------------------------------------------- 1 | /* 2 | * $Id: patricia.h,v 1.6 2005/12/07 20:53:01 dplonka Exp $ 3 | * Dave Plonka 4 | * 5 | * This product includes software developed by the University of Michigan, 6 | * Merit Network, Inc., and their contributors. 7 | * 8 | * This file had been called "radix.h" in the MRT sources. 9 | * 10 | * I renamed it to "patricia.h" since it's not an implementation of a general 11 | * radix trie. Also, pulled in various requirements from "mrt.h" and added 12 | * some other things it could be used as a standalone API. 13 | */ 14 | 15 | #ifndef _PATRICIA_H 16 | #define _PATRICIA_H 17 | 18 | #define HAVE_IPV6 19 | 20 | /* typedef unsigned int u_int; */ 21 | typedef void (*void_fn_t)(); 22 | /* { from defs.h */ 23 | #define prefix_touchar(prefix) ((u_char *)&(prefix)->add.sin) 24 | #define MAXLINE 1024 25 | #define BIT_TEST(f, b) ((f) & (b)) 26 | /* } */ 27 | 28 | #define addroute make_and_lookup 29 | 30 | #include /* for u_* definitions (on FreeBSD 5) */ 31 | 32 | #include /* for EAFNOSUPPORT */ 33 | #ifndef EAFNOSUPPORT 34 | # defined EAFNOSUPPORT WSAEAFNOSUPPORT 35 | # include 36 | #else 37 | # include /* for struct in_addr */ 38 | #endif 39 | 40 | #include /* for AF_INET */ 41 | 42 | /* { from mrt.h */ 43 | 44 | typedef struct _prefix4_t { 45 | u_short family; /* AF_INET | AF_INET6 */ 46 | u_short bitlen; /* same as mask? */ 47 | int ref_count; /* reference count */ 48 | struct in_addr sin; 49 | } prefix4_t; 50 | 51 | typedef struct _prefix_t { 52 | u_short family; /* AF_INET | AF_INET6 */ 53 | u_short bitlen; /* same as mask? */ 54 | int ref_count; /* reference count */ 55 | union { 56 | struct in_addr sin; 57 | struct in6_addr sin6; 58 | } add; 59 | } prefix_t; 60 | 61 | /* } */ 62 | 63 | typedef struct _patricia_node_t { 64 | u_int bit; /* flag if this node used */ 65 | prefix_t *prefix; /* who we are in patricia tree */ 66 | struct _patricia_node_t *l, *r; /* left and right children */ 67 | struct _patricia_node_t *parent;/* may be used */ 68 | void *data; /* pointer to data */ 69 | void *user1; /* pointer to usr data (ex. route flap info) */ 70 | } patricia_node_t; 71 | 72 | typedef struct _patricia_tree_t { 73 | patricia_node_t *head; 74 | u_int maxbits; /* for IP, 32 bit addresses */ 75 | int num_active_node; /* for debug purpose */ 76 | } patricia_tree_t; 77 | 78 | 79 | patricia_node_t *patricia_search_exact (patricia_tree_t *patricia, prefix_t *prefix); 80 | patricia_node_t *patricia_search_best (patricia_tree_t *patricia, prefix_t *prefix); 81 | patricia_node_t * patricia_search_best2 (patricia_tree_t *patricia, prefix_t *prefix, 82 | int inclusive); 83 | patricia_node_t *patricia_lookup (patricia_tree_t *patricia, prefix_t *prefix); 84 | void patricia_remove (patricia_tree_t *patricia, patricia_node_t *node); 85 | patricia_tree_t *New_Patricia (int maxbits); 86 | void Clear_Patricia (patricia_tree_t *patricia, void_fn_t func); 87 | void Destroy_Patricia (patricia_tree_t *patricia, void_fn_t func); 88 | void patricia_process (patricia_tree_t *patricia, void_fn_t func); 89 | prefix_t *New_Prefix(int family, void *dest, int bitlen); 90 | /* { from demo.c */ 91 | 92 | prefix_t * 93 | ascii2prefix (int family, char *string); 94 | 95 | patricia_node_t * 96 | make_and_lookup (patricia_tree_t *tree, int afi, char *string); 97 | 98 | /* } */ 99 | 100 | #define PATRICIA_MAXBITS (sizeof(struct in6_addr) * 8) 101 | #define PATRICIA_NBIT(x) (0x80 >> ((x) & 0x7f)) 102 | #define PATRICIA_NBYTE(x) ((x) >> 3) 103 | 104 | #define PATRICIA_DATA_GET(node, type) (type *)((node)->data) 105 | #define PATRICIA_DATA_SET(node, value) ((node)->data = (void *)(value)) 106 | 107 | #define PATRICIA_WALK(Xhead, Xnode) \ 108 | do { \ 109 | patricia_node_t *Xstack[PATRICIA_MAXBITS+1]; \ 110 | patricia_node_t **Xsp = Xstack; \ 111 | patricia_node_t *Xrn = (Xhead); \ 112 | while ((Xnode = Xrn)) { \ 113 | if (Xnode->prefix) 114 | 115 | #define PATRICIA_WALK_ALL(Xhead, Xnode) \ 116 | do { \ 117 | patricia_node_t *Xstack[PATRICIA_MAXBITS+1]; \ 118 | patricia_node_t **Xsp = Xstack; \ 119 | patricia_node_t *Xrn = (Xhead); \ 120 | while ((Xnode = Xrn)) { \ 121 | if (1) 122 | 123 | #define PATRICIA_WALK_BREAK { \ 124 | if (Xsp != Xstack) { \ 125 | Xrn = *(--Xsp); \ 126 | } else { \ 127 | Xrn = (patricia_node_t *) 0; \ 128 | } \ 129 | continue; } 130 | 131 | #define PATRICIA_WALK_END \ 132 | if (Xrn->l) { \ 133 | if (Xrn->r) { \ 134 | *Xsp++ = Xrn->r; \ 135 | } \ 136 | Xrn = Xrn->l; \ 137 | } else if (Xrn->r) { \ 138 | Xrn = Xrn->r; \ 139 | } else if (Xsp != Xstack) { \ 140 | Xrn = *(--Xsp); \ 141 | } else { \ 142 | Xrn = (patricia_node_t *) 0; \ 143 | } \ 144 | } \ 145 | } while (0) 146 | 147 | #endif /* _PATRICIA_H */ 148 | -------------------------------------------------------------------------------- /repgen.c: -------------------------------------------------------------------------------- 1 | 2 | /* DNS Response Generator */ 3 | 4 | #include 5 | #include 6 | 7 | #define NETMAP_WITH_LIBS 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | 20 | #include "patricia.h" 21 | 22 | 23 | #define NM_BURST_MAX 1024 24 | 25 | #define ADDR4COPY(s, d) *(((u_int32_t *)(d))) = *(((u_int32_t *)(s))) 26 | #define ADDRCMP(s, d) (*(((u_int32_t *)(d))) == *(((u_int32_t *)(s)))) 27 | 28 | 29 | int verbose = 0; 30 | int vale_rings = 0; 31 | 32 | 33 | struct repgen { 34 | char * intf; 35 | char * qname; 36 | }; 37 | 38 | struct repgen repgen; 39 | 40 | struct vnfapp { 41 | pthread_t tid; 42 | 43 | int rx_fd, tx_fd; 44 | int rx_q, tx_q; 45 | char * rx_if, * tx_if; 46 | struct netmap_ring * rx_ring, * tx_ring; 47 | 48 | void * data; 49 | }; 50 | 51 | 52 | /* DNS related codes */ 53 | struct dns_hdr { 54 | u_int16_t id; 55 | u_int16_t flag; 56 | u_int16_t qn_count; 57 | u_int16_t an_count; 58 | u_int16_t ns_count; 59 | u_int16_t ar_count; 60 | 61 | char qname[0]; 62 | } __attribute__ ((__packed__)); 63 | #define DNS_FLAG_QR 0x8000 64 | #define DNS_FLAG_OP 0x1800 65 | #define DNS_FLAG_OP_STANDARD 0x0000 66 | #define DNS_FLAG_OP_INVERSE 0x0800 67 | #define DNS_FLAG_OP_STATUS 0x1000 68 | #define DNS_FLAG_AA 0x0400 69 | #define DNS_FLAG_TC 0x0200 70 | #define DNS_FLAG_RD 0x0100 71 | #define DNS_FLAG_RA 0x0080 72 | #define DNS_FLAG_RC 0x000F 73 | #define DNS_FLAG_RC_NOERR 0x0000 74 | #define DNS_FLAG_RC_FMTERR 0x0001 75 | #define DNS_FLAG_RC_SRVERR 0x0002 76 | #define DNS_FLAG_RC_NMERR 0x0003 77 | #define DNS_FLAG_RC_NOIMPL 0x0004 78 | #define DNS_FLAG_RC_DENIED 0x0005 79 | 80 | #define DNS_IS_QUERY(d) (!(ntohs ((d)->flag) & DNS_FLAG_QR)) 81 | #define DNS_IS_RESPONSE(d) ((ntohs ((d)->flag) & DNS_FLAG_QR)) 82 | #define DNS_IS_AUTHORITATIVE(d) (ntohs ((d)->flag) & DNS_FLAG_AA) 83 | 84 | 85 | /* DNS Queries related codes */ 86 | 87 | struct dns_qname_ftr { 88 | u_int16_t rep_type; 89 | u_int16_t rep_class; 90 | } __attribute__ ((__packed__)); 91 | #define DNS_REP_TYPE_A 1 92 | #define DNS_REP_TYPE_NS 2 93 | #define DNS_REP_TYPE_CNAME 5 94 | #define DNS_REP_TYPE_PTR 12 95 | #define DNS_REP_TYPE_MX 15 96 | #define DNS_REP_TYPE_AAAA 28 97 | #define DNS_REP_TYPE_ANY 255 98 | 99 | #define DNS_REP_CLASS_INTERNET 1 100 | 101 | 102 | static uint16_t 103 | checksum(const void * data, uint16_t len, uint32_t sum) 104 | { 105 | const uint8_t *addr = data; 106 | uint32_t i; 107 | 108 | /* Checksum all the pairs of bytes first... */ 109 | for (i = 0; i < (len & ~1U); i += 2) { 110 | sum += (u_int16_t)ntohs(*((u_int16_t *)(addr + i))); 111 | if (sum > 0xFFFF) 112 | sum -= 0xFFFF; 113 | } 114 | /* 115 | * If there's a single byte left over, checksum it, too. 116 | * Network byte order is big-endian, so the remaining byte is 117 | * the high byte. 118 | */ 119 | 120 | if (i < len) { 121 | sum += addr[i] << 8; 122 | if (sum > 0xFFFF) 123 | sum -= 0xFFFF; 124 | } 125 | 126 | return sum; 127 | } 128 | 129 | static u_int16_t 130 | wrapsum(u_int32_t sum) 131 | { 132 | sum = ~sum & 0xFFFF; 133 | return (htons(sum)); 134 | } 135 | 136 | 137 | void 138 | set_ether_header (struct ether_header * eth, __u8 * dst_mac, __u8 * src_mac) 139 | { 140 | memcpy (eth->ether_dhost, dst_mac, ETH_ALEN); 141 | memcpy (eth->ether_shost, src_mac, ETH_ALEN); 142 | eth->ether_type = htons (ETHERTYPE_IP); 143 | 144 | return; 145 | } 146 | 147 | void 148 | set_ip_header (struct ip * ip, struct in_addr * dst_addr, 149 | struct in_addr * src_addr, size_t len) 150 | { 151 | 152 | ip->ip_v = IPVERSION; 153 | ip->ip_hl = 5; 154 | ip->ip_id = 0; 155 | ip->ip_tos = IPTOS_LOWDELAY; 156 | ip->ip_len = htons (len); 157 | ip->ip_id = 0; 158 | ip->ip_off = htons (IP_DF); 159 | ip->ip_ttl = 16; 160 | ip->ip_p = IPPROTO_UDP; 161 | ip->ip_dst = *dst_addr; 162 | ip->ip_src = *src_addr; 163 | ip->ip_sum = 0; 164 | ip->ip_sum = wrapsum (checksum (ip, sizeof (*ip), 0)); 165 | 166 | return; 167 | } 168 | 169 | void 170 | set_udp_header (struct udphdr * udp, size_t len) 171 | { 172 | 173 | udp->uh_sport = htons (53); 174 | udp->uh_dport = htons (53); 175 | 176 | udp->uh_ulen = htons (len); 177 | 178 | udp->uh_sum = 0; /* no udp checksum */ 179 | 180 | return; 181 | } 182 | 183 | 184 | u_int 185 | xmit (struct vnfapp * va) 186 | { 187 | int len; 188 | u_int burst, m, k; 189 | 190 | struct netmap_slot * ts; 191 | struct ether_header * eth; 192 | struct ip * ip; 193 | struct udphdr * udp; 194 | struct dns_hdr * dns; 195 | struct dns_qname_ftr * ftr; 196 | 197 | __u8 smac[ETH_ALEN] = { 0x01, 0x01, 0x01, 0x02, 0x02, 0x02 }; 198 | //__u8 dmac[ETH_ALEN] = { 0x01, 0x01, 0x01, 0x03, 0x03, 0x03 }; 199 | __u8 dmac[ETH_ALEN] = { 0xa0, 0x36, 0x9f, 0x2b, 0x27, 0xd0 }; 200 | struct in_addr saddr = { 0x0100000A }; 201 | struct in_addr daddr = { 0x0200000A }; 202 | 203 | 204 | burst = NM_BURST_MAX; 205 | 206 | m = nm_ring_space (va->tx_ring); 207 | if (m < burst) 208 | burst = m; 209 | 210 | m = burst; 211 | 212 | 213 | #define QNAME_LEN 29 214 | len = sizeof (struct ether_header) + 215 | sizeof (struct ip) + 216 | sizeof (struct udphdr) + 217 | sizeof (struct dns_hdr) + 218 | QNAME_LEN + sizeof (struct dns_qname_ftr); 219 | 220 | 221 | while (burst-- > 0) { 222 | 223 | ts = &va->tx_ring->slot[k]; 224 | 225 | eth = (struct ether_header *) 226 | NETMAP_BUF (va->tx_ring, ts->buf_idx); 227 | 228 | set_ether_header (eth, dmac, smac); 229 | 230 | ip = (struct ip *) (eth + 1); 231 | set_ip_header (ip, &daddr, &saddr, 232 | len - sizeof (struct ether_header)); 233 | 234 | udp = (struct udphdr *) (((char *) ip) + (ip->ip_hl * 4)); 235 | set_udp_header (udp, len - sizeof (struct ether_header) - 236 | sizeof (struct ip)); 237 | 238 | dns = (struct dns_hdr *) (udp + 1); 239 | 240 | dns->id = 0x0002; 241 | dns->flag = htons (0x0100); 242 | dns->qn_count = htons (2); 243 | dns->an_count = 0; 244 | dns->ns_count = 0; 245 | dns->ar_count = 0; 246 | 247 | dns->qname[0] = 0x03; 248 | dns->qname[1] = 'a'; 249 | dns->qname[2] = 'a'; 250 | dns->qname[3] = 'a'; 251 | dns->qname[4] = 0x03; 252 | dns->qname[5] = 'b'; 253 | dns->qname[6] = 'b'; 254 | dns->qname[7] = 'b'; 255 | dns->qname[8] = 0x03; 256 | dns->qname[9] = 'c'; 257 | dns->qname[10] = 'c'; 258 | dns->qname[11] = 'c'; 259 | dns->qname[12] = 0x03; 260 | dns->qname[13] = 'd'; 261 | dns->qname[14] = 'd'; 262 | dns->qname[15] = 'd'; 263 | dns->qname[16] = 0x03; 264 | dns->qname[17] = 'e'; 265 | dns->qname[18] = 'e'; 266 | dns->qname[19] = 'e'; 267 | dns->qname[20] = 0x03; 268 | dns->qname[21] = 'f'; 269 | dns->qname[22] = 'f'; 270 | dns->qname[23] = 'f'; 271 | dns->qname[24] = 0x03; 272 | dns->qname[25] = 'g'; 273 | dns->qname[26] = 'g'; 274 | dns->qname[27] = 'g'; 275 | dns->qname[28] = 0x00; 276 | 277 | /* 278 | dns->qname[0] = 0x03; 279 | dns->qname[1] = 'w'; 280 | dns->qname[2] = 'w'; 281 | dns->qname[3] = 'w'; 282 | dns->qname[4] = 0x04; 283 | dns->qname[5] = 'k'; 284 | dns->qname[6] = 'a'; 285 | dns->qname[7] = 'm'; 286 | dns->qname[8] = 'e'; 287 | dns->qname[9] = 0x03; 288 | dns->qname[10] = 'n'; 289 | dns->qname[11] = 'e'; 290 | dns->qname[12] = 't'; 291 | dns->qname[13] = 0x00; 292 | */ 293 | 294 | ftr = (struct dns_qname_ftr *)(&dns->qname[QNAME_LEN]); 295 | ftr->rep_type = htons (DNS_REP_TYPE_A); 296 | ftr->rep_class = htons (DNS_REP_CLASS_INTERNET); 297 | 298 | ts->len = len; 299 | k = nm_ring_next (va->tx_ring, k); 300 | 301 | } 302 | 303 | va->tx_ring->head = va->tx_ring->cur = k; 304 | 305 | return m; 306 | } 307 | 308 | void * 309 | processing_thread (void * param) 310 | { 311 | struct vnfapp * va = param; 312 | 313 | D ("rxfd=%d, txfd=%d, rxq=%d, txq=%d, rxif=%s, txif=%s, " 314 | "rxring=%p, txring=%p", 315 | va->rx_fd, va->tx_fd, va->rx_q, va->tx_q, va->rx_if, va->tx_if, 316 | va->rx_ring, va->tx_ring); 317 | 318 | pthread_detach (pthread_self ()); 319 | 320 | while (1) { 321 | 322 | xmit (va); 323 | if (va->tx_q == 0) { 324 | ioctl (va->tx_fd, NIOCTXSYNC, va->rx_q); 325 | } 326 | } 327 | 328 | return NULL; 329 | } 330 | 331 | 332 | void 333 | usage (void) 334 | { 335 | printf ("Usage of repgen\n" 336 | "\t" "-i : Interface name\n" 337 | "\t" "-q : Query name\n" 338 | "\t" "-e : Number of Rings of a vale port\n" 339 | "\t" "-f : Daemon mode\n" 340 | "\t" "-v : Verbose mode\n" 341 | "\t" "-h : Print this help\n" 342 | ""); 343 | 344 | 345 | return; 346 | } 347 | 348 | int 349 | main (int argc, char ** argv) 350 | { 351 | int n, ch, f_flag = 0; 352 | 353 | struct nm_desc * nm; 354 | 355 | repgen.intf = NULL; 356 | repgen.qname = NULL; 357 | 358 | while ((ch = getopt (argc, argv, "i:e:s:fvh")) != -1) { 359 | switch (ch) { 360 | case 'i' : 361 | repgen.intf = optarg; 362 | break; 363 | case 'e' : 364 | vale_rings = atoi (optarg); 365 | if (vale_rings > 4) { 366 | D ("Max of number of vale rings is 4."); 367 | return -1; 368 | } 369 | break; 370 | case 'f' : 371 | f_flag = 1; 372 | break; 373 | case 'v' : 374 | verbose = 1; 375 | break; 376 | case 'h' : 377 | default : 378 | usage (); 379 | return -1; 380 | } 381 | } 382 | if (!repgen.intf) { 383 | D ("interface is not specified"); 384 | return -1; 385 | } 386 | 387 | nm = nm_open (repgen.intf, NULL, 0, NULL); 388 | if (!nm) { 389 | D ("failed to open %s", repgen.intf); 390 | return -1; 391 | } 392 | 393 | /* Assign threads for each RX rings of Right interface */ 394 | for (n = nm->first_tx_ring; n < nm->last_tx_ring; n++) { 395 | struct vnfapp * va; 396 | va = (struct vnfapp *) malloc (sizeof (struct vnfapp)); 397 | memset (va, 0, sizeof (struct vnfapp)); 398 | 399 | va->rx_q = n; 400 | va->tx_q = n; 401 | va->rx_if = repgen.intf; 402 | va->tx_if = repgen.intf; 403 | va->rx_fd = nm->fd; 404 | va->tx_fd = nm->fd; 405 | va->tx_ring = NETMAP_TXRING (nm->nifp, va->tx_q); 406 | pthread_create (&va->tid, NULL, processing_thread, va); 407 | } 408 | 409 | 410 | if (f_flag) { 411 | daemon (0, 0); 412 | } 413 | 414 | while (1) { 415 | /* controlling module will be implemented here */ 416 | sleep (100); 417 | } 418 | 419 | return 0; 420 | } 421 | -------------------------------------------------------------------------------- /ssap_trie.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* simple suffix base and add only patricia trie */ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | #include "list.h" 12 | 13 | struct ssap_trie { 14 | struct list_head next; 15 | struct list_head sibling; 16 | 17 | char ch; 18 | void * data; 19 | }; 20 | 21 | struct ssap_trie * 22 | ssap_trie_new (char ch) { 23 | 24 | struct ssap_trie * trie; 25 | 26 | trie = (struct ssap_trie *) malloc (sizeof (struct ssap_trie)); 27 | memset (trie, 0, sizeof (struct ssap_trie)); 28 | INIT_LIST_HEAD (&trie->next); 29 | INIT_LIST_HEAD (&trie->sibling); 30 | trie->ch = ch; 31 | 32 | return trie; 33 | } 34 | 35 | 36 | struct ssap_trie * 37 | ssap_trie_search (struct ssap_trie * root, char * word) 38 | { 39 | int n; 40 | struct ssap_trie * trie; 41 | struct list_head * tmp_head, * cur, * next; 42 | 43 | trie = root; 44 | tmp_head = &root->next; 45 | 46 | for (n = strlen (word); n >= 0; n--) { 47 | 48 | if (tmp_head != &root->next && list_empty (tmp_head)) { 49 | /* longest matched! */ 50 | return trie; 51 | } 52 | 53 | list_for_each_safe (cur, next, tmp_head) { 54 | trie = list_entry (cur, struct ssap_trie, sibling); 55 | 56 | if (trie->ch == word[n]) { 57 | /* match! next character! */ 58 | tmp_head = &trie->next; 59 | goto next_depth; 60 | } 61 | 62 | } 63 | 64 | /* there is no next character leaf. not found! */ 65 | return NULL; 66 | 67 | next_depth:; 68 | } 69 | 70 | if (n < 0 && list_empty (tmp_head)) { 71 | /* perfect match. query = match name !! */ 72 | return trie; 73 | } 74 | 75 | return NULL; 76 | } 77 | 78 | int 79 | ssap_trie_walk (struct ssap_trie * root, void (*func)(void *)) 80 | { 81 | struct ssap_trie * trie; 82 | struct list_head * tmp_head, * cur, * next; 83 | 84 | tmp_head = &root->next; 85 | 86 | if (root->data) { 87 | func (root->data); 88 | } 89 | 90 | list_for_each_safe (cur, next, tmp_head) { 91 | trie = list_entry (cur, struct ssap_trie, sibling); 92 | ssap_trie_walk (trie, func); 93 | } 94 | 95 | return 0; 96 | } 97 | 98 | int 99 | ssap_trie_add (struct ssap_trie * root, char * word, void * data) 100 | { 101 | int n; 102 | struct ssap_trie * trie, * parent; 103 | struct list_head * tmp_head, * cur, * next; 104 | 105 | parent = root; 106 | tmp_head = &root->next; 107 | 108 | for (n = strlen (word); n >= 0; n--) { 109 | 110 | list_for_each_safe (cur, next, tmp_head) { 111 | trie = list_entry (cur, struct ssap_trie, sibling); 112 | 113 | if (trie->ch == word[n]) { 114 | /* match! next character! */ 115 | goto next_depth; 116 | } 117 | } 118 | 119 | /* there is no next character. add new node! */ 120 | trie = ssap_trie_new (word[n]); 121 | if (n == 0) { 122 | /* edge leaf. add data. */ 123 | trie->data = data; 124 | } 125 | list_add_tail (&trie->sibling, &parent->next); 126 | 127 | next_depth: 128 | tmp_head = &trie->next; 129 | parent = trie; 130 | } 131 | 132 | return 1; 133 | } 134 | 135 | 136 | -------------------------------------------------------------------------------- /systemd/d4c.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Dirty Deeds Done Dirt Cheap 3 | After=network.target 4 | 5 | [Service] 6 | Type=simple 7 | EnvironmentFile=/etc/default/d4c 8 | ExecStartPost=/sbin/ifconfig eth4 promisc 9 | ExecStartPost=/sbin/ifconfig eth5 promisc 10 | ExecStart=/usr/local/bin/d4c $D4C_OPTS 11 | KillMode=process 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | -------------------------------------------------------------------------------- /systemd/etc-default-d4c: -------------------------------------------------------------------------------- 1 | # Envairoment values for d4c. 2 | # 3 | 4 | D4C_OPTS= -r eth4 -l eth5 5 | --------------------------------------------------------------------------------