1/** 2 * \file 3 * \brief Helper functoin and additional tools used by libbfdmux 4*/ 5/* 6 * Copyright (c) 2009, 2010, ETH Zurich. 7 * All rights reserved. 8 * 9 * This file is distributed under the terms in the attached LICENSE file. 10 * If you do not find this file, copies can be found by writing to: 11 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 12 */ 13 14#ifndef DOXYGEN 15// exclude system headers from documentation 16 17//#include <errno.h> 18#include <stdlib.h> 19#include <string.h> 20 21#endif // DOXYGEN 22 23#include <barrelfish/barrelfish.h> 24 25#include <bfdmuxtools/tools.h> 26 27/** 28 * \brief Finds the index of the most significant 1-bit in 'value' 29 * @param value The integer to be analyzed 30 * @return The index of the most significant 1-bit in value (bits numbered 1..64); 0 if value = 0. 31 */ 32 33//inline int find_msb(uint64_t value); 34 35inline int 36find_msb(uint64_t value) 37{ 38 int msb; 39 uint32_t lo, 40 hi; 41 42 msb = 0; 43 lo = (uint32_t) value; 44 hi = (uint32_t) (value >> 32); 45 46 // Perform binary search for most significant bit 47 if (hi) { 48 msb |= 0x20; 49 lo = hi & 0xFFFF; 50 hi = hi >> 16; 51 } else { 52 hi = lo >> 16; 53 lo = lo & 0xFFFF; 54 } 55 if (hi) { 56 msb |= 0x10; 57 lo = hi & 0x00FF; 58 hi = hi >> 8; 59 } else { 60 hi = lo >> 8; 61 lo = lo & 0x00FF; 62 } 63 if (hi) { 64 msb |= 0x08; 65 lo = hi & 0x000F; 66 hi = hi >> 4; 67 } else { 68 hi = lo >> 4; 69 lo = lo & 0x000F; 70 } 71 if (hi) { 72 msb |= 0x04; 73 lo = hi & 0x0003; 74 hi = hi >> 2; 75 } else { 76 hi = lo >> 2; 77 lo = lo & 0x0003; 78 } 79 if (hi) { 80 msb |= 0x02; 81 lo = hi & 0x0001; 82 hi = hi >> 1; 83 } else { 84 hi = lo >> 1; 85 lo = lo & 0x0001; 86 } 87 if (hi) { 88 msb |= 0x01; 89 } 90 91 return msb + (value >> msb); // Modifies bit numbering from 0..63 92 // to range from 1..64 93} 94 95/** 96 * \brief Returns a string with pos-1 spaces and a '^' character. Used to indicate error position in filter string! 97 * @param pos The position to point at 98 * @return A string with a '^' character at the given position. Caller should free memory after use! 99 */ 100char * 101get_error_position_string(int pos) 102{ 103 int i = 0; 104 char *res = malloc(pos + 1); 105 while ((i + 1) < pos) { 106 res[i] = ' '; 107 i++; 108 } 109 res[i] = '^'; 110 res[i + 1] = 0; 111 return res; 112} 113 114/** 115 * \brief Parses a string consisting of hex digits to a byte array 116 * @param str The string to be parsed, e.g. "fe01abc9" 117 * @return A byte array, e.g. 0xfe 0x01 0xab 0xc9. Caller should free the array after use! 118 119uint8_t * 120parse_hex_input(char *str) 121{ 122 char hex[3]; 123 int i; 124 int len = strlen(str); 125 if ((len % 2) != 0) { 126 return 0; 127 } 128 129 len = len / 2; 130 char *res = malloc(len); 131 hex[2] = 0; 132 for (i = 0; i < len; i++) { 133 hex[0] = str[i * 2]; 134 hex[1] = str[i * 2 + 1]; 135 errno = 0; 136 char *endptr = (char *) &hex; 137 uint8_t val = strtol((char *) &hex, &endptr, 16); 138 if ((errno == 0) && (endptr != (char *) &hex)) { 139 res[i] = val; 140 } else { 141 free(res); 142 return 0; 143 } 144 } 145 return (uint8_t *) res; 146} 147*/ 148 149/* 150 * Filter builder 151 */ 152 153#define MAC_ADDR_SIZE 6 154 155static inline bool if_any_mac(struct eth_addr addr){ 156 157 int i; 158 for(i = 0; i < MAC_ADDR_SIZE; i++) { 159 if(addr.addr[i] != 0xff) { 160 return false; 161 } 162 } 163 return true; 164} 165 166/* 167 * SrcMac field: size 48 bit offset = 0 168 * DstMac field: size 48 bit offset = 48 169 */ 170/* 171 * This creates a Mac filter with a dst address 172 */ 173 174char* build_dst_mac_filter(struct eth_addr dst) 175{ 176 uint32_t first_four = 0; 177 uint16_t last_two = 0; 178 size_t max_len = 64; 179 char *filter = malloc(max_len); 180 filter[0] = 0x0; 181 182 first_four = (uint32_t) dst.addr[3]; 183 first_four |= ((uint32_t) dst.addr[2]) << 8; 184 first_four |= ((uint32_t) dst.addr[1]) << 16; 185 first_four |= ((uint32_t) dst.addr[0]) << 24; 186 last_two = (uint16_t) dst.addr[5]; 187 last_two |= ((uint16_t) dst.addr[4]) << 8; 188 189 if(!if_any_mac(dst)) { 190 snprintf(filter, max_len, "int32[0]==%"PRIu32"&&int16[4]==%"PRIu16, 191 first_four, last_two); 192 } 193 if (strlen(filter) == 0) { 194 snprintf(filter, max_len, "1"); 195 } 196 return filter; 197 198} 199 200char* build_src_mac_filter(struct eth_addr src) 201{ 202 uint32_t first_four = 0; 203 uint16_t last_two = 0; 204 size_t max_len = 64; 205 char *filter = malloc(max_len); 206 filter[0] = 0x0; 207 208 first_four = (uint32_t) src.addr[3]; 209 first_four |= ((uint32_t) src.addr[2]) << 8; 210 first_four |= ((uint32_t) src.addr[1]) << 16; 211 first_four |= ((uint32_t) src.addr[0]) << 24; 212 last_two = (uint16_t) src.addr[5]; 213 last_two |= ((uint16_t) src.addr[4]) << 8; 214 215 if(!if_any_mac(src)) { 216 snprintf(filter, max_len, "int32[6]==%"PRIu32"&&int16[10]==%"PRIu16, 217 first_four, last_two); 218 } 219 if (strlen(filter) == 0) { 220 snprintf(filter, max_len, "1"); 221 } 222 return filter; 223 224} 225 226/* 227 * SrcIP filed: size=32bit, offset=12Bytes 228 * DstIP field: size=32bit, offset=16Bytes 229 */ 230/** 231 * \brief IPv4 filter template 232 * 233 * Create an IPv4 filter based on a source IP and a destination IP. The source IP is a 32bit field in the 234 * IPv4 header starting at offset 12Bytes, the destination IP is also a 32bit field starting at 16Bytes. 235 * @param srcip Filter packets coming from this source IP (BFDMUX_IP_ADDR_ANY for any source) 236 * @param dstip Filter packets going to this destination IP (BFDMUX_IP_ADDR_ANY for any target) 237 * @return A filter string. Caller has to free it after use. 238 */ 239/* FIXME: It is assumed that if it is non-ARP packet then it should be IP packet. 240 * So no check in Ethernet packet header to see if it is IP or not. PS */ 241char * 242build_ipv4_filter(addr_t srcip, addr_t dstip) 243{ 244 size_t max_len = 64; 245 char *filter = malloc(max_len); 246 filter[0] = 0x0; // strlen(filter) = 0; 247 if (srcip != BFDMUX_IP_ADDR_ANY) 248 snprintf(filter, max_len, "int32[26]==%"PRIu32"", (uint32_t) srcip); 249 if (dstip != BFDMUX_IP_ADDR_ANY) { 250 if (srcip != BFDMUX_IP_ADDR_ANY) 251 snprintf(filter + strlen(filter), max_len, "&&"); 252 snprintf(filter + strlen(filter), max_len, "int32[30]==%"PRIu32"", 253 (uint32_t) dstip); 254 } 255 256 if (strlen(filter) == 0) { // srcip == BFDMUX_IP_ADDR_ANY && dstip == 257 // BFDMUX_IP_ADDR_ANY 258 snprintf(filter, max_len, "1"); 259 } 260 return filter; 261} 262 263/* 264 * Protocol field: size=8bit, offset=9Bytes (in IP Header) 265 * ICMP Protocol number: 0x01 266 */ 267/** 268 * \brief ICMP filter template 269 * 270 * Create a generic ICMP packet filter 271 * @return A filter sting. Caller has to free it after use. 272 */ 273char * 274build_icmp_filter(void) 275{ 276 size_t max_len = 128; 277 char *filter = malloc(max_len); 278 snprintf(filter, max_len, "int8[23]==%u", 0x01); 279 280 return filter; 281} 282 283/** 284 * \brief ICMP over IPv4 filter template 285 * 286 * This function build a ICMP over IPv4 filter based on the given arguments 287 * using the build_tcp_filter and build_ipv4_filter helper functions. 288 * @param srcip Source IP-Address to filter for (BFDMUX_IP_ADDR_ANY for any) 289 * @param dstip Destination IP-Address to filter for (BFDMUX_IP_ADDR_ANY for any) 290 * @return A filter string. Caller has to free it after use. 291 */ 292char * 293build_ipv4_icmp_filter(addr_t srcip, addr_t dstip) 294{ 295 char *ip_filter = build_ipv4_filter(srcip, dstip); 296 char *icmp_filter = build_icmp_filter(); 297 int filter_len = strlen(ip_filter) + strlen(icmp_filter) + 2 + 1; 298 /* 2: &&, 1: zero byte */ 299 300 char *filter = malloc(filter_len); 301 snprintf(filter, filter_len, "%s&&%s", ip_filter, icmp_filter); 302 free(ip_filter); 303 free(icmp_filter); 304 return filter; 305} 306 307 308 309 310/* 311 * Protocol field: size=8bit, offset=9Bytes (in IP Header) 312 * SrcPort field: size=16bit, offset=20Bytes (with IP Header) 313 * DstPort field: size=16bit, offset=22Bytes (with IP Header) 314 * TCP Protocol number: 0x06 315 */ 316/** 317 * \brief TCP filter template 318 * 319 * Create a TCP filter based on the source and destination TCP Port. This filter looks for the TCP protocol number (0x06) 320 * in the IP header and sets the 16bit long source port field positioned at offset 20Bytes (with IP header) and the 16bit long 321 * destination port filed positioned at offset 22Bytes to the given arguments. 322 * @param srcport TCP source port to filter on (PORT_ANY for any port) 323 * @param dstport TCP destination port to filter on (PORT_ANY for any port) 324 * @return A filter sting. Caller has to free it after use. 325 */ 326char * 327build_tcp_filter(port_t srcport, port_t dstport) 328{ 329 size_t max_len = 128; 330 char *filter = malloc(max_len); 331 snprintf(filter, max_len, "int8[23]==%u", 0x06); 332 333 if (srcport != PORT_ANY) 334 snprintf(filter + strlen(filter), max_len, "&&int16[34]==%u", 335 (uint16_t) srcport); 336 if (dstport != PORT_ANY) { 337 snprintf(filter + strlen(filter), max_len, "&&int16[36]==%u", 338 (uint16_t) dstport); 339 } 340 341 return filter; 342} 343 344/* 345 * Protocol field: size=8bit, offset=9Bytes (in IP Header) 346 * SrcPort field: size=16bit, offset=20Bytes (with IP Header) 347 * DstPort field: size=16bit, offset=22Bytes (with IP Header) 348 * UDP Protocol number: 0x11 349 */ 350/** 351 * \brief UDP filter template 352 * 353 * Create a UDP filter based on the source and destination UDP Port. This filter looks for the UDP protocol number (0x11) 354 * in the IP header and sets the 16bit long source port field positioned at offset 20Bytes (with IP header) and the 16bit long 355 * destination port filed positioned at offset 22Bytes to the given arguments. 356 * @param srcport UDP source port to filter on (PORT_ANY for any port) 357 * @param dstport UDP destination port to filter on (PORT_ANY for any port) 358 * @return A filter sting. Caller has to free it after use. 359 */ 360char * 361build_udp_filter(port_t srcport, port_t dstport) 362{ 363 size_t max_len = 128; 364 char *filter = malloc(max_len); 365 snprintf(filter, max_len, "int8[23]==%u", 0x11); 366 367 if (srcport != PORT_ANY) 368 snprintf(filter + strlen(filter), max_len, "&&int16[34]==%u", 369 (uint16_t) srcport); 370 if (dstport != PORT_ANY) { 371 snprintf(filter + strlen(filter), max_len, "&&int16[36]==%u", 372 (uint16_t) dstport); 373 } 374 375 return filter; 376} 377 378/** 379 * \brief TCP over IPv4 filter template 380 * 381 * This function build a TCP over IPv4 filter based on the given arguments using the build_tcp_filter and build_ipv4_filter 382 * helper functions. 383 * @param srcip Source IP-Address to filter for (BFDMUX_IP_ADDR_ANY for any) 384 * @param dstip Destination IP-Address to filter for (BFDMUX_IP_ADDR_ANY for any) 385 * @param srcport Source TCP port to filter for (PORT_ANY for any) 386 * @param dstport Destination TCP port to filter for (PORT_ANY for any) 387 * @return A filter string. Caller has to free it after use. 388 */ 389char * 390build_ipv4_tcp_filter(addr_t srcip, addr_t dstip, port_t srcport, 391 port_t dstport) 392{ 393 char *ip_filter = build_ipv4_filter(srcip, dstip); 394 char *tcp_filter = build_tcp_filter(srcport, dstport); 395 int filter_len = strlen(ip_filter) + strlen(tcp_filter) + 2 + 1; // 2: 396 // 397 // 398 // &&, 399 // 1: 400 // zero 401 // byte 402 char *filter = malloc(filter_len); 403 snprintf(filter, filter_len, "%s&&%s", ip_filter, tcp_filter); 404 free(ip_filter); 405 free(tcp_filter); 406 return filter; 407} 408 409/** 410 * \brief UDP over IPv4 filter template 411 * 412 * This function build a UDP over IPv4 filter based on the given arguments using the build_tcp_filter and build_ipv4_filter 413 * helper functions. 414 * @param srcip Source IP-Address to filter for (BFDMUX_IP_ADDR_ANY for any) 415 * @param dstip Destination IP-Address to filter for (BFDMUX_IP_ADDR_ANY for any) 416 * @param srcport Source UDP port to filter for (PORT_ANY for any) 417 * @param dstport Destination UDP port to filter for (PORT_ANY for any) 418 * @return A filter string. Caller has to free it after use. 419 */ 420char * 421build_ipv4_udp_filter(addr_t srcip, addr_t dstip, port_t srcport, 422 port_t dstport) 423{ 424 char *ip_filter = build_ipv4_filter(srcip, dstip); 425 char *udp_filter = build_udp_filter(srcport, dstport); 426 size_t filter_len = strlen(ip_filter) + strlen(udp_filter) + 2 + 1; // 2: 427 // 428 // 429 // &&, 430 // 1: 431 // zero 432 // byte 433 char *filter = malloc(filter_len); 434 snprintf(filter, filter_len, "%s&&%s", ip_filter, udp_filter); 435 free(ip_filter); 436 free(udp_filter); 437 return filter; 438} 439 440char* build_ether_dst_ipv4_udp_filter(struct eth_addr dst, addr_t srcip, 441 addr_t dstip, port_t srcport, port_t dstport) 442{ 443 char *mac_filter = build_dst_mac_filter(dst); 444 char *ip_filter = build_ipv4_filter(srcip, dstip); 445 char *udp_filter = build_udp_filter(srcport, dstport); 446 size_t filter_len = strlen(mac_filter) + strlen(ip_filter) + 447 strlen(udp_filter) + 4 + 1; 448 // 4: 2 * &&, 1: zero byte 449 char *filter = malloc(filter_len); 450 snprintf(filter, filter_len, "%s&&%s&&%s", mac_filter, ip_filter, 451 udp_filter); 452 free(mac_filter); 453 free(ip_filter); 454 free(udp_filter); 455 return filter; 456 457} 458 459char* build_ether_dst_ipv4_tcp_filter(struct eth_addr dst, addr_t srcip, 460 addr_t dstip, port_t srcport, port_t dstport) 461{ 462 char *mac_filter = build_dst_mac_filter(dst); 463 char *ip_filter = build_ipv4_filter(srcip, dstip); 464 char *tcp_filter = build_tcp_filter(srcport, dstport); 465 size_t filter_len = strlen(mac_filter) + strlen(ip_filter) + 466 strlen(tcp_filter) + 4 + 1; 467 // 4: 2 * &&, 1: zero byte 468 char *filter = malloc(filter_len); 469 snprintf(filter, filter_len, "%s&&%s&&%s", mac_filter, ip_filter, 470 tcp_filter); 471 free(mac_filter); 472 free(ip_filter); 473 free(tcp_filter); 474 return filter; 475} 476 477char* build_ether_src_ipv4_udp_filter(struct eth_addr src, addr_t srcip, 478 addr_t dstip, port_t srcport, port_t dstport) 479{ 480 char *mac_filter = build_src_mac_filter(src); 481 char *ip_filter = build_ipv4_filter(srcip, dstip); 482 char *udp_filter = build_udp_filter(srcport, dstport); 483 size_t filter_len = strlen(mac_filter) + 484 strlen(ip_filter) + strlen(udp_filter) + 4 + 1; 485 // 4: 2 * &&, 1: zero byte 486 char *filter = malloc(filter_len); 487 snprintf(filter, filter_len, "%s&&%s&&%s", mac_filter, ip_filter, 488 udp_filter); 489 free(mac_filter); 490 free(ip_filter); 491 free(udp_filter); 492 return filter; 493 494} 495 496char* build_ether_src_ipv4_tcp_filter(struct eth_addr src, addr_t srcip, 497 addr_t dstip, port_t srcport, port_t dstport) 498{ 499 char *mac_filter = build_src_mac_filter(src); 500 char *ip_filter = build_ipv4_filter(srcip, dstip); 501 char *tcp_filter = build_tcp_filter(srcport, dstport); 502 size_t filter_len = strlen(mac_filter) + 503 strlen(ip_filter) + strlen(tcp_filter) + 4 + 1; 504 // 4: 2 * &&, 1: zero byte 505 char *filter = malloc(filter_len); 506 snprintf(filter, filter_len, "%s&&%s&&%s", mac_filter, ip_filter, 507 tcp_filter); 508 free(mac_filter); 509 free(ip_filter); 510 free(tcp_filter); 511 return filter; 512} 513 514char* build_generic_arp_reply_filter(void) 515{ 516 size_t max_len = 128; 517 char *filter = malloc(max_len); 518 assert(filter); 519 memset(filter, 0, max_len); 520 snprintf(filter, max_len, "int16[12]==%u", 0x0806 /* ETHTYPE_ARP */); 521 /* FIXME: why following filter is broken? 522 * Question is, what is the correct location of value 0x0002? */ 523/* snprintf(filter, max_len, "int16[12]==%u&&int16[20]==%u", (0x0806), 524 (0x0002)); 525*/ 526 527 /* The hardcoded values for protocol field are already 528 * in the network order. */ 529 return filter; 530} 531 532char* build_arp_transmit_filter(struct eth_addr src) 533{ 534 char *mac = build_src_mac_filter(src); 535 size_t max_len = 128; 536 char *filter = malloc(max_len); 537 assert(mac); 538 assert(filter); 539 memset(filter, 0, max_len); 540 snprintf(filter, max_len, "int16[12]==%u&&%s", 0x0806, mac); 541 /*FIXME: why these values are not htons()? */ 542 return filter; 543} 544 545