bool netif_add_ipv6_address(netif_t *netif, const ipv6_address_t *address, const ipv6_address_t *netmask, const ipv6_state_t state) { ipv6_alias_t *ipv6; if (LOG_ENABLE(LOG_NETWORK_INTERFACE, LOG_INFO)) { LOG_IPV6(address, address_str); LOG_IPV6(netmask, netmask_str); LOG_PRINTLN(LOG_NETWORK_INTERFACE, LOG_INFO, ("add_ipv6_address: address = %s", address_str)); LOG_PRINTLN(LOG_NETWORK_INTERFACE, LOG_INFO, ("add_ipv6_address: netmask = %s", netmask_str)); } /** * Concatinate: * _____________ __________________ * | | | | * | netif->ipv6 |===>| old ipv6 or NULL | * |_____________| |__________________| * _____________ __________ __________________ * | | | | | | * | netif->ipv6 |===>| new ipv6 |===>| old ipv6 or NULL | * |_____________| |__________| |__________________| */ ipv6 = netif_create_ipv6_alias(); ipv6->next = netif->ipv6; netif->ipv6 = ipv6; ipv6->address = address != NULL ? *address : IPV6_ADDRESS_NULL; ipv6->netmask = netmask != NULL ? *netmask : IPV6_ADDRESS_NULL; ipv6->state = state; return true; }
bool do_simulation(config_t *config) { netif_t netif; raw_packet_t raw_packet; packet_t *packet; uint32_t i; //uint32_t k; if (config->netif_size < 1 || config->netif[0].vlan_size < 1 || !config->netif[0].vlan[0].ntp_configured || config->netif[0].vlan[0].ntp.client_size < 1) { LOG_PRINTLN(LOG_SIM, LOG_ERROR, ("No ARP config in configuration file! Abort")); return false; } if (!netif_init(&netif, config->netif[0].name)) { return false; } raw_packet_init(&raw_packet); LOG_PRINTLN(LOG_SIM, LOG_INFO, ("Create ARP request")); packet = create_arp_request(&netif, config->netif[0].vlan[0].vid, &(config->netif[0].vlan[0].ntp.client[0].mac_address), &(config->netif[0].vlan[0].ntp.client[0].ipv4_address)); LOG_PACKET(LOG_SIM, LOG_INFO, packet, ("TX packet")); /* encode */ LOG_PRINTLN(LOG_SIM, LOG_INFO, ("Encode packet")); if (packet_encode(&netif, packet, &raw_packet)) { LOG_PRINTLN(LOG_SIM, LOG_INFO, ("Successfully encoded packet")); } else { LOG_PRINTLN(LOG_SIM, LOG_ERROR, ("Error encoding packet")); object_release(packet); return false; } for (i = 0; i < 0xff; i++) { raw_packet.data[raw_packet.len] = i; raw_packet.len++; LOG_RAW_PACKET(LOG_SIM, LOG_INFO, &raw_packet, ("TX raw")); /* send */ netif_frame_send(&netif, &raw_packet); usleep(50000); } object_release(packet); return true; }
/**************************************************************************** * main * * @param argc argument count * @param argv argument list * @return int return code ***************************************************************************/ int main(int argc, char *argv[]) { config_t config; char config_file[NAME_MAX+1]; bool fflag = false; /* option: config-file */ int opt; /* argument for getopt() as a single integer */ /* program without arguments */ if (argc == 1) { usage(argc, argv, NULL); } /* first character ':' of getopt()'s optstring sets opterr=0 and returns ':' to indicate a missing option argument or '?' to indicate a unrecognised option */ while ((opt = getopt(argc, argv, ":l:df:")) != -1) { switch (opt) { /* option: config-file */ case 'f': strcpy(config_file, optarg); fflag = true; break; /* missing option argument */ case ':': usage(argc, argv, OPT_REQUIRED); break; /* unrecognised option */ case '?': usage(argc, argv, OPT_UNRECOGNISED); break; default: usage(argc, argv, NULL); } } log_init(); /* option: config-file */ if (!fflag) { strcpy(config_file, CONFIG_FILE_NAME); } LOG_PRINTLN(LOG_SIM, LOG_INFO, ("Using config-file \"%s\"", config_file)); if (!config_file_parse(config_file, &config)) { printf("Error in parsing the file!\n"); exit(EXIT_FAILURE); } do_simulation(&config); fprintf(stderr, "Exit!\n"); return 0; }
void dns_header_free(header_t *header) { LOG_PRINTLN(LOG_HEADER_DNS, LOG_DEBUG, ("DNS header free 0x%016" PRIxPTR, (unsigned long) header)); header_storage_free(header); }
header_t * dns_header_decode(netif_t *netif, packet_t *packet, raw_packet_t *raw_packet, packet_offset_t offset) { dns_header_t *dns = dns_header_new(); packet_offset_t field_offset; if (raw_packet->len < (offset + DNS_HEADER_LEN)) { LOG_PRINTLN(LOG_HEADER_DNS, LOG_ERROR, ("decode DNS header: size too small (present=%u, required=%u)", raw_packet->len - offset, DNS_HEADER_LEN)); DNS_FAILURE_EXIT; } /* fetch header */ uint8_to_uint16(&(dns->id), &(raw_packet->data[offset + DNS_HEADER_OFFSET_ID])); uint8_to_uint16(&(dns->flags.raw), &(raw_packet->data[offset + DNS_HEADER_OFFSET_FLAGS])); uint8_to_uint16(&(dns->qd_count), &(raw_packet->data[offset + DNS_HEADER_OFFSET_QD_COUNT])); uint8_to_uint16(&(dns->an_count), &(raw_packet->data[offset + DNS_HEADER_OFFSET_AN_COUNT])); uint8_to_uint16(&(dns->ns_count), &(raw_packet->data[offset + DNS_HEADER_OFFSET_NS_COUNT])); uint8_to_uint16(&(dns->ar_count), &(raw_packet->data[offset + DNS_HEADER_OFFSET_AR_COUNT])); field_offset = offset + DNS_HEADER_LEN; /* question section */ if (dns->qd_count > 0) { dns->qd = dns_query_new(); if (!dns_header_decode_query(raw_packet, offset, &field_offset, dns->qd_count, dns->qd)) { dns_query_free(dns->qd); DNS_FAILURE_EXIT; } } /* answer records section */ if (dns->an_count > 0) { dns->an = dns_rr_new(); if (!dns_header_decode_rr(raw_packet, offset, &field_offset, dns->an_count, dns->an)) { dns_rr_free(dns->an); DNS_FAILURE_EXIT; } } /* authority records section */ if (dns->ns_count > 0) { dns->ns = dns_rr_new(); if (!dns_header_decode_rr(raw_packet, offset, &field_offset, dns->ns_count, dns->ns)) { dns_rr_free(dns->ns); DNS_FAILURE_EXIT; } } /* additional records section */ if (dns->ar_count > 0) { dns->ar = dns_rr_new(); if (!dns_header_decode_rr(raw_packet, offset, &field_offset, dns->ar_count, dns->ar)) { dns_rr_free(dns->ar); DNS_FAILURE_EXIT; } } return (header_t *) dns; }
/** * @brief */ bool netif_frame_select(netif_t *netif, uint32_t timeout) { fd_set readfds; /* list of monitored file descriptors */ int numfds; /* number of ready file descriptors */ struct timeval tv = { /* time structure used in select() */ .tv_sec = 0, .tv_usec = timeout }; FD_ZERO(&readfds); FD_SET(netif->socket, &readfds); /* wait until a "file descriptor" is ready (returns immediately after ready) or wait until time is up. Return value is number of ready "file descriptors", 0 (time is up) or -1 (error) */ numfds = select(netif->socket + 1, &readfds, NULL, NULL, &tv); switch (numfds) { /* error */ case -1: LOG_PRINTLN(LOG_NETWORK_INTERFACE, LOG_ERROR, ("can't monitor socket: %s", strerror(errno))); return false; /* time up */ case 0: break; /* fd ready */ default: return true; } return false; } /** * @brief sends layer 2 frame */ void netif_frame_send(netif_t *netif, raw_packet_t *raw_packet) { if (send(netif->socket, raw_packet->data, raw_packet->len, 0 /* no flags */) < 0) { LOG_PRINTLN(LOG_NETWORK_INTERFACE, LOG_ERROR, ("can't send packet: %s", strerror(errno))); } }
void udpv4_header_free(header_t *header) { if (header->next != NULL) header->next->klass->free(header->next); LOG_PRINTLN(LOG_HEADER_UDPV4, LOG_DEBUG, ("UDPv4 header free 0x%016" PRIxPTR, (unsigned long) header)); header_storage_free(header); }
udpv4_header_t * udpv4_header_new(void) { udpv4_header_t *header = (udpv4_header_t *) header_storage_new(&storage); LOG_PRINTLN(LOG_HEADER_UDPV4, LOG_DEBUG, ("UDPv4 header new 0x%016" PRIxPTR, (unsigned long) header)); return header; }
/***************************************************************************** * Header */ dns_header_t * dns_header_new(void) { dns_header_t *header = (dns_header_t *) header_storage_new(&storage); LOG_PRINTLN(LOG_HEADER_DNS, LOG_DEBUG, ("DNS header new 0x%016" PRIxPTR, (unsigned long) header)); return header; }
bool netif_add_vid(netif_t *netif, const uint16_t vid) { vlan_t *vlan; if (LOG_ENABLE(LOG_NETWORK_INTERFACE, LOG_INFO)) { LOG_PRINTLN(LOG_NETWORK_INTERFACE, LOG_INFO, ("add_vlan: vid = %u", vid)); } if (netif->vlan != NULL) { LOG_PRINTLN(LOG_NETWORK_INTERFACE, LOG_WARNING, ("overwrite VLAN vid = %u", netif->vlan->vid)); } vlan = netif_create_vlan(); netif->vlan = vlan; return true; }
static bool netif_clear_receive_buffer(netif_t *netif) { raw_packet_t raw_packet; bool running = true; uint32_t counter = 0; ssize_t len; raw_packet_init(&raw_packet); /* receive data from receive buffer until buffer is empty */ while (running) { len = recv(netif->socket, raw_packet.data, sizeof(raw_packet.data), MSG_DONTWAIT); switch (len) { case -1: /* no data received */ if (errno == EAGAIN || errno == EWOULDBLOCK) { LOG_PRINTLN(LOG_NETWORK_INTERFACE, LOG_DEBUG, ("receive buffer cleared!")); return true; } /* other errors */ LOG_PRINTLN(LOG_NETWORK_INTERFACE, LOG_DEBUG, ("can't clear receive buffer: %s", strerror(errno))); running = false; break; case 0: /* peer closed connection */ LOG_PRINTLN(LOG_NETWORK_INTERFACE, LOG_DEBUG, ("can't clear receive buffer: Hey! Socket should be connectionless!")); running = false; break; default: /* handle received data */ counter++; LOG_PRINTLN(LOG_NETWORK_INTERFACE, LOG_DEBUG, ("receive buffer: clear frame nr. %u", counter)); break; } } return false; }
bool netif_add_mac_address(netif_t *netif, const mac_address_t *mac) { if (LOG_ENABLE(LOG_NETWORK_INTERFACE, LOG_INFO)) { LOG_MAC(mac, mac_str); LOG_PRINTLN(LOG_NETWORK_INTERFACE, LOG_INFO, ("add_mac_address: mac = %s", mac_str)); } netif->mac = *mac; return true; }
void DigitalInputEvent::init(uint8_t pin) { _pin = pin; pinMode(pin, INPUT); // Receive runtime events RUNTIME.Attach(this); LOG_PRINTLN(DEBUG_INFO, "DigitalInputEvent initialized"); }
bool netif_add_vlan(netif_t *netif, vlan_t *vlan) { if (netif->vlan != NULL) { LOG_PRINTLN(LOG_NETWORK_INTERFACE, LOG_WARNING, ("overwrite VLAN vid = %u", netif->vlan->vid)); } netif->vlan = vlan; return true; }
/** * @brief This function is used to receive a Layer 2 RAW-Frame. */ bool netif_frame_receive(netif_t *netif, raw_packet_t *raw_packet) { if (netif_frame_select(netif, NETIF_SELECT_WAIT_USECS)) { if ((raw_packet->len = recv(netif->socket, raw_packet->data, ETH_MAX_FRAME_SIZE, 0 /* no flags */)) < 0) { LOG_PRINTLN(LOG_NETWORK_INTERFACE, LOG_ERROR, ("can't receive packet: %s", strerror(errno))); return false; } return true; } return false; }
/**************************************************************************** * udpv4_header_decode * * @param this logical packet to be written * @param raw_packet raw packet to be read * @param offset offset from origin to udp packet ***************************************************************************/ header_t * udpv4_header_decode(netif_t *netif, packet_t *packet, raw_packet_t *raw_packet, packet_offset_t offset) { udpv4_header_t *udpv4 = udpv4_header_new(); uint16_t low_port; uint16_t high_port; if (raw_packet->len < (offset + UDPV4_HEADER_LEN)) { LOG_PRINTLN(LOG_HEADER_UDPV4, LOG_ERROR, ("decode UDPv4 header: size too small (present=%u, required=%u)", raw_packet->len - offset, UDPV4_HEADER_LEN)); UDPV4_FAILURE_EXIT; } /* fetch */ uint8_to_uint16(&(udpv4->src_port), &(raw_packet->data[offset + UDPV4_HEADER_OFFSET_SRC_PORT])); uint8_to_uint16(&(udpv4->dest_port), &(raw_packet->data[offset + UDPV4_HEADER_OFFSET_DEST_PORT])); uint8_to_uint16(&(udpv4->len), &(raw_packet->data[offset + UDPV4_HEADER_OFFSET_LEN])); uint8_to_uint16(&(udpv4->checksum), &(raw_packet->data[offset + UDPV4_HEADER_OFFSET_CHECKSUM])); /* decide */ if (udpv4->src_port < udpv4->dest_port) { low_port = udpv4->src_port; high_port = udpv4->dest_port; } else { low_port = udpv4->dest_port; high_port = udpv4->src_port; } switch (low_port) { case PORT_DNS: udpv4->header.next = dns_header_decode(netif, packet, raw_packet, offset + UDPV4_HEADER_LEN); break; default: break; } /* if next header is filled in, return... */ if (udpv4->header.next != NULL) { return (header_t *) udpv4; } /* ...otherwise try again with high port */ switch (high_port) { case PORT_DNS: udpv4->header.next = dns_header_decode(netif, packet, raw_packet, offset + UDPV4_HEADER_LEN); break; default: UDPV4_FAILURE_EXIT; } if (udpv4->header.next == NULL) { UDPV4_FAILURE_EXIT; } // TODO: Checksum (over pseudo-header, udp-header and payload) check return (header_t *) udpv4; }
bool netif_add_ipv4_address(netif_t *netif, const ipv4_address_t *address, const ipv4_address_t *netmask, const ipv4_address_t *broadcast, const ipv4_address_t *gateway) { ipv4_alias_t *ipv4; if (LOG_ENABLE(LOG_NETWORK_INTERFACE, LOG_INFO)) { LOG_IPV4(address, address_str); LOG_IPV4(broadcast, broadcast_str); LOG_IPV4(netmask, netmask_str); LOG_PRINTLN(LOG_NETWORK_INTERFACE, LOG_INFO, ("add_ipv4_address: address = %s", address_str)); LOG_PRINTLN(LOG_NETWORK_INTERFACE, LOG_INFO, ("add_ipv4_address: netmask = %s", netmask_str)); LOG_PRINTLN(LOG_NETWORK_INTERFACE, LOG_INFO, ("add_ipv4_address: broadcast = %s", broadcast_str)); } /** * Concatinate: * _____________ __________________ * | | | | * | netif->ipv4 |===>| old ipv4 or NULL | * |_____________| |__________________| * _____________ __________ __________________ * | | | | | | * | netif->ipv4 |===>| new ipv4 |===>| old ipv4 or NULL | * |_____________| |__________| |__________________| */ ipv4 = netif_create_ipv4_alias(); ipv4->next = netif->ipv4; netif->ipv4 = ipv4; ipv4->address = address != NULL ? *address : IPV4_ADDRESS_NULL; ipv4->netmask = netmask != NULL ? *netmask : IPV4_ADDRESS_NULL; ipv4->broadcast = broadcast != NULL ? *broadcast : IPV4_ADDRESS_NULL; ipv4->gateway = gateway != NULL ? *gateway : IPV4_ADDRESS_NULL; return true; }
static bool dns_header_decode_query(raw_packet_t *raw_packet, packet_offset_t header_offset, packet_offset_t *field_offset, uint16_t count, dns_query_t *query) { dns_label_t *label; for (; count > 0; count--) { if (raw_packet->len < (*field_offset + DNS_QUERY_MIN_LEN)) { LOG_PRINTLN(LOG_HEADER_DNS, LOG_ERROR, ("decode DNS query: size too small (present=%" PRIoffset ", required=%" PRIoffset ", offset=%" PRIoffset "/%x)", raw_packet->len - *field_offset, DNS_QUERY_MIN_LEN, *field_offset, *field_offset)); return false; } /* qname */ label = dns_label_new(); if (!dns_header_decode_label(raw_packet, header_offset, field_offset, label)) { dns_label_free(label); return false; } query->qname = label; /* qtype + qclass */ uint8_to_uint16(&(query->qtype), &(raw_packet->data[*field_offset + DNS_QUERY_OFFSET_QTYPE])); uint8_to_uint16(&(query->qclass), &(raw_packet->data[*field_offset + DNS_QUERY_OFFSET_QCLASS])); *field_offset += DNS_QUERY_SIZE; /* not the last query */ if (count > 1) { query->next = dns_query_new(); query = query->next; } } return true; }
packet_len_t udpv4_header_encode(netif_t *netif, packet_t *packet, raw_packet_t *raw_packet, packet_offset_t offset) { ipv4_header_t *ipv4; udpv4_header_t *udpv4; packet_len_t len; /* udp-header and payload length */ uint16_t ipv4_pseudo_size = 0; packet_offset_t pseudo_offset = 0; uint32_t zero = 0; if (packet->tail->klass->type != PACKET_TYPE_IPV4 || packet->tail->next == NULL || packet->tail->next->klass->type != PACKET_TYPE_UDPV4) { return 0; } ipv4 = (ipv4_header_t *) packet->tail; udpv4 = (udpv4_header_t *) packet->tail->next; packet->tail = udpv4->header.next; /* decide */ switch (udpv4->dest_port) { case PORT_DNS: len = dns_header_encode(netif, packet, raw_packet, offset + UDPV4_HEADER_LEN); break; default: return 0; } if (len == 0) { return 0; } /* add udp-header to payload */ len += UDPV4_HEADER_LEN; udpv4->len = len; uint16_to_uint8(&(raw_packet->data[offset + UDPV4_HEADER_OFFSET_SRC_PORT]), &(udpv4->src_port)); /**< UDP Source Port */ uint16_to_uint8(&(raw_packet->data[offset + UDPV4_HEADER_OFFSET_DEST_PORT]), &(udpv4->dest_port)); /**< UDP Destination port */ uint16_to_uint8(&(raw_packet->data[offset + UDPV4_HEADER_OFFSET_LEN]), &(udpv4->len)); /**< Packet Length (UDP Header + Payload) */ /* reset checksum of raw packet */ memcpy(&(raw_packet->data[offset + UDPV4_HEADER_OFFSET_CHECKSUM]), &(zero), sizeof(udpv4->checksum)); /* calculate checksum over pseudo-ip-header, udp-header and payload */ /* fill in pseudo-ip-header. the pseudo-ip-header will be overwritten by the real ip-header afterwards! */ /* IPv4 pseudo-header */ if (ipv4->version == IPV4_HEADER_VERSION) { pseudo_offset = UDPV4_HEADER_PSEUDO_IPV4_SRC; ipv4_pseudo_size = len; raw_packet->data[offset - UDPV4_HEADER_PSEUDO_IPV4_PROTOCOL] = ipv4->protocol; /**< Protocol */ uint16_to_uint8(&(raw_packet->data[offset - UDPV4_HEADER_PSEUDO_IPV4_LEN]), &(ipv4_pseudo_size)); /**< UDP Length */ memcpy(&(raw_packet->data[offset - UDPV4_HEADER_PSEUDO_IPV4_SRC]), &(ipv4->src), IPV4_ADDRESS_LEN); /**< Source IPv4 Address */ memcpy(&(raw_packet->data[offset - UDPV4_HEADER_PSEUDO_IPV4_DEST]), &(ipv4->dest), IPV4_ADDRESS_LEN); /**< Destination IPv4 Address */ memcpy(&(raw_packet->data[offset - UDPV4_HEADER_PSEUDO_IPV4_ZERO]), &(zero), 1); /**< Zeros */ } else { return 0; } /* check whether the UDP datagram length is an odd number */ if (len % 2 == 1) { /* add a padding zero for checksum calculation and increase length by one */ raw_packet->data[offset + len] = 0; len += 1; } /* data = pseudo-ip-header + udp-header + payload * len = pseudo-ip-header + udp-header + payload */ udpv4->checksum = raw_packet_calc_checksum((uint16_t *) &(raw_packet->data[offset - pseudo_offset]), len + pseudo_offset); LOG_PRINTLN(LOG_HEADER_UDPV4, LOG_DEBUG, ("encode UDP packet: checksum = 0x%04x, offset = %u, pseudo_offset = %u, size = %u", ntohs(udpv4->checksum), offset, pseudo_offset, len)); /* set pseudo-ip-header to zero */ memset(&(raw_packet->data[offset - pseudo_offset]), 0, pseudo_offset); /* write checksum down to raw packet */ uint16_to_uint8(&(raw_packet->data[offset + UDPV4_HEADER_OFFSET_CHECKSUM]), &(udpv4->checksum)); /**< Checksum */ return len; }
netif_init_bpf(netif_t *netif, const char *name, uint16_t port, struct sock_filter *filter, int filter_len) #endif { bool result = true; struct ifaddrs *ifas; struct ifaddrs *ifa; #if __FreeBSD__ struct ifreq ifr; /* ioctl call to get VID */ struct vlanreq vreq; /* ioctl call to get VID */ #elif __linux__ struct ifreq ifr; /* ioctl call to get MAC address*/ struct rtnl_link_stats *stats; struct vlan_ioctl_args ifv; /* ioctl call to get VID */ struct sockaddr_ll addr; /* to bind packet socket to interface */ struct sockaddr_in dummy_addr; /* to bind dummy socket to interface */ struct sock_fprog prog; /* to attach to filter */ #endif /* string copy name */ strncpy(netif->name, name, NETIF_NAME_SIZE); /* set to zero */ memcpy(netif->mac.addr, MAC_ADDRESS_NULL.addr, MAC_ADDRESS_LEN); netif->vlan = NULL; netif->ipv4 = NULL; netif->ipv6 = NULL; /*** get the index of the interface ***/ netif->index = if_nametoindex(netif->name); if (netif->index == 0) { LOG_PRINTLN(LOG_NETWORK_INTERFACE, LOG_ERROR, ("interface '%s' is not known", netif->name)); return false; } /* create socket */ if ((netif->socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) { LOG_ERRNO(LOG_NETWORK_INTERFACE, LOG_ERROR, errno, ("socket failed")); return false; } /* get interface addresses */ if (getifaddrs(&ifas) != 0) { LOG_ERRNO(LOG_NETWORK_INTERFACE, LOG_ERROR, errno, ("getifaddrs failed")); return false; } for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) { if ((ifa->ifa_addr) == NULL) continue; if ((ifa->ifa_flags & IFF_UP) == 0) continue; /* network interface name matches */ if (strcmp(name, ifa->ifa_name) == 0) { switch (ifa->ifa_addr->sa_family) { case AF_INET: netif_add_ipv4_address(netif, IPV4_ADDRESS(&(INADDR(ifa->ifa_addr)->sin_addr)), IPV4_ADDRESS(&(INADDR(ifa->ifa_netmask)->sin_addr)), IPV4_ADDRESS(&(INADDR(ifa->ifa_broadaddr)->sin_addr)), NULL); break; case AF_INET6: netif_add_ipv6_address(netif, IPV6_ADDRESS(&(INADDR6(ifa->ifa_addr)->sin6_addr)), IPV6_ADDRESS(&(INADDR6(ifa->ifa_netmask)->sin6_addr)), IPV6_STATE_VALID); break; #if __FreeBSD__ case AF_LINK: netif_add_mac_address(netif, MAC_ADDRESS(LLADDR(LADDR(ifa->ifa_addr)))); bzero((char *) &ifr, sizeof(ifr)); bzero((char *) &vreq, sizeof(vreq)); strncpy(ifr.ifr_name, netif->name, NETIF_NAME_SIZE); ifr.ifr_data = (caddr_t) &vreq; if (ioctl(sockfd, SIOCGETVLAN, &ifr) != -1) { netif_add_vid(netif, vreq.vlr_tag); } break; #elif __linux__ case AF_PACKET: stats = ifa->ifa_data; LOG_PRINTLN(LOG_NETWORK_INTERFACE, LOG_DEBUG, ("tx packet: %" PRIu32 " rx packet: %" PRIu32 " tx bytes: %" PRIu32 " rx bytes: %" PRIu32, stats->tx_packets, stats->rx_packets, stats->tx_bytes, stats->rx_bytes)); /* get MAC address, see netdevice(7) */ bzero((char *) &ifr, sizeof(ifr)); strncpy(ifr.ifr_name, netif->name, NETIF_NAME_SIZE); if (ioctl(netif->socket, SIOCGIFHWADDR, &ifr) != -1) { netif_add_mac_address(netif, MAC_ADDRESS(LLADDR(LADDR(ifr.ifr_hwaddr.sa_data)))); bzero((char *) &ifv, sizeof(ifv)); ifv.cmd = GET_VLAN_VID_CMD; strncpy(ifv.device1, netif->name, sizeof(ifv.device1)); if (ioctl(netif->socket, SIOCGIFVLAN, &ifv) != -1) { netif_add_vid(netif, ifv.u.VID); } } else { LOG_PRINTLN(LOG_NETWORK_INTERFACE, LOG_ERROR, ("couldn't get MAC address")); result = false; goto netif_init_exit; } break; #endif default: continue; } } } /* bind packet socket to interface */ bzero(&addr, sizeof(addr)); addr.sll_family = AF_PACKET; addr.sll_protocol = htons(ETH_P_ALL); addr.sll_ifindex = netif->index; if (bind(netif->socket, (struct sockaddr *) &addr, sizeof(addr)) < 0) { close(netif->socket); LOG_ERRNO(LOG_NETWORK_INTERFACE, LOG_ERROR, errno, ("can't bind packet socket to interface")); return false; } #if __FreeBSD__ #elif __linux__ if (filter != NULL) { prog.filter = filter; prog.len = filter_len; if (setsockopt(netif->socket, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0) { close(netif->socket); LOG_ERRNO(LOG_NETWORK_INTERFACE, LOG_ERROR, errno, ("can't add BPF filter")); return false; } } #endif if (netif->ipv4 != NULL && port > 0) { /* create dummy socket ***/ if ((netif->dummy_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { close(netif->socket); LOG_ERRNO(LOG_NETWORK_INTERFACE, LOG_ERROR, errno, ("can't create dummy socket")); return false; } /* bind dummy socket to interface */ bzero(&dummy_addr, sizeof(dummy_addr)); dummy_addr.sin_family = AF_INET; dummy_addr.sin_addr.s_addr = netif->ipv4->address.addr32; dummy_addr.sin_port = htons(port); if (bind(netif->dummy_socket, (struct sockaddr *) &dummy_addr, sizeof(dummy_addr)) < 0) { close(netif->socket); close(netif->dummy_socket); LOG_ERRNO(LOG_NETWORK_INTERFACE, LOG_ERROR, errno, ("can't bind dummy socket to interface")); return false; } } /* clear receive buffer */ if (!netif_clear_receive_buffer(netif)) { return false; } netif_init_exit: freeifaddrs(ifas); return result; }
static bool dns_header_decode_rr(raw_packet_t *raw_packet, packet_offset_t header_offset, packet_offset_t *field_offset, uint16_t count, dns_rr_t *rr) { dns_label_t *label; for (; count > 0; count--) { if (raw_packet->len < (*field_offset + DNS_RR_MIN_LEN)) { LOG_PRINTLN(LOG_HEADER_DNS, LOG_ERROR, ("decode DNS resource record: size too small (present=%" PRIoffset ", required=%" PRIoffset ", offset=%" PRIoffset "/%x)", raw_packet->len, *field_offset + DNS_RR_MIN_LEN, *field_offset, *field_offset)); return false; } /* name */ DNS_LABEL_NEW rr->name = label; uint8_to_uint16(&(rr->type), &(raw_packet->data[*field_offset + DNS_RR_OFFSET_TYPE])); /**< Type */ uint8_to_uint16(&(rr->klass), &(raw_packet->data[*field_offset + DNS_RR_OFFSET_CLASS])); /**< Class */ uint8_to_uint32(&(rr->ttl), &(raw_packet->data[*field_offset + DNS_RR_OFFSET_TTL])); /**< TTL */ uint8_to_uint16(&(rr->rdlength), &(raw_packet->data[*field_offset + DNS_RR_OFFSET_RDLENGTH])); /**< RD Length */ *field_offset += DNS_RR_SIZE; /* decode type */ /* TODO: check offset range and return false if out-of-range! */ switch (rr->type) { case DNS_TYPE_A: memcpy(&(rr->a.ipv4_address), &(raw_packet->data[*field_offset]), rr->rdlength); *field_offset += rr->rdlength; break; case DNS_TYPE_NS: DNS_LABEL_NEW rr->ns.nsdname = label; break; case DNS_TYPE_CNAME: DNS_LABEL_NEW rr->cname.cname = label; break; case DNS_TYPE_SOA: DNS_LABEL_NEW rr->soa.mname = label; DNS_LABEL_NEW rr->soa.rname = label; uint8_to_uint32(&(rr->soa.serial), &(raw_packet->data[*field_offset + DNS_RR_SOA_OFFSET_SERIAL])); uint8_to_uint32(&(rr->soa.refresh), &(raw_packet->data[*field_offset + DNS_RR_SOA_OFFSET_REFRESH])); uint8_to_uint32(&(rr->soa.retry), &(raw_packet->data[*field_offset + DNS_RR_SOA_OFFSET_RETRY])); uint8_to_uint32(&(rr->soa.expire), &(raw_packet->data[*field_offset + DNS_RR_SOA_OFFSET_EXPIRE])); uint8_to_uint32(&(rr->soa.minimum), &(raw_packet->data[*field_offset + DNS_RR_SOA_OFFSET_MINIMUM])); *field_offset += DNS_RR_SOA_SIZE; break; case DNS_TYPE_PTR: DNS_LABEL_NEW rr->ptr.ptrdname = label; break; case DNS_TYPE_MX: uint8_to_uint16(&(rr->mx.preference), &(raw_packet->data[*field_offset + DNS_RR_MX_OFFSET_PREFERENCE])); *field_offset += DNS_RR_MX_SIZE; DNS_LABEL_NEW rr->mx.exchange = label; break; case DNS_TYPE_OPT: default: *field_offset += rr->rdlength; break; } /* not the last resource record */ if (count > 1) { rr->next = dns_rr_new(); rr = rr->next; } } return true; }