Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
/****************************************************************************
 * 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;
}
Пример #6
0
/**
 * @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;
}
Пример #10
0
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;
}
Пример #11
0
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;
}
Пример #12
0
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");
}
Пример #14
0
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;
}
Пример #15
0
/**
 * @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;
}
Пример #17
0
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;
}
Пример #20
0
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;
}