Ejemplo n.º 1
0
static void multi_link_modify_link(const struct nlmsghdr *nlh, 
        uint32_t probe_pipe, uint8_t unique){
    struct ifinfomsg *ifi = mnl_nlmsg_get_payload(nlh);
    struct nlattr *tb[IFLA_MAX + 1] = {};
    uint8_t iface_state = 0;
    struct multi_link_info *li = NULL;
	struct multi_link_info_static *li_static = NULL;
    pthread_attr_t detach_attr;
    uint8_t wireless_mode = 0;
    uint8_t *if_name;

    mnl_attr_parse(nlh, sizeof(*ifi), multi_link_fill_rtattr, tb);

    if (!tb[IFLA_IFNAME]) {
        MULTI_DEBUG_PRINT_SYSLOG(stderr, "Missing interface name\n");
        return;
    }

    if_name = (uint8_t*) mnl_attr_get_str(tb[IFLA_IFNAME]);

    if (!strncmp(if_name, "veth", 4) ||
        ifi->ifi_type == ARPHRD_VOID ||
        (ifi->ifi_type == ARPHRD_NONE && strncmp(if_name,"wwan", 4)) ||
        ifi->ifi_type == ARPHRD_TUNNEL ||
        ifi->ifi_flags & IFF_LOOPBACK)
        return;

    if(tb[IFLA_OPERSTATE]){
        iface_state = mnl_attr_get_u8(tb[IFLA_OPERSTATE]);

        /* Check linux/Documentation/networking/operstates.txt. IFF_RUNNING 
         * wraps both UP and UNKNOWN*/
        if (ifi->ifi_flags & IFF_RUNNING){
        //IF_OPER_UP == 6, defined in linux/if.h, chaos with includes
        //if(iface_state == 6){
            MULTI_DEBUG_PRINT_SYSLOG(stderr, "Interface %s (%u) is RUNNING, "
                    "length %u\n", if_name, ifi->ifi_index,
                    multi_link_num_links);
 
            if((wireless_mode = multi_link_check_wlan_mode(if_name)))
                if(wireless_mode == 6){
                    MULTI_DEBUG_PRINT_SYSLOG(stderr, "Interface %s is monitor, "
                            "ignoring\n", if_name);
                    return;
                }
 
            LIST_FIND_CUSTOM(li, &multi_link_links_2, next, &(ifi->ifi_index),
                    multi_cmp_ifidx);

            if(li != NULL){
                if(li->state == LINK_UP_STATIC_IFF){
                    MULTI_DEBUG_PRINT_SYSLOG(stderr, "Interface %s (idx %u) has "
                        "gone from UP to RUNNING\n", if_name, ifi->ifi_index);
                    li->state = GOT_IP_STATIC;
                } else
                    MULTI_DEBUG_PRINT_SYSLOG(stderr,"Interface %s (idx %u) has "
                        "already been seen. Ignoring event\n", if_name, 
                        ifi->ifi_index);
                return;
            }

            if(multi_link_num_links < MAX_NUM_LINKS){
                TAILQ_FIND_CUSTOM(li_static, &multi_shared_static_links,
                        list_ptr, if_name, multi_cmp_devname);

                if(li_static != NULL){
                    if(li_static->proto == PROTO_IGNORE){
                        MULTI_DEBUG_PRINT_SYSLOG(stderr, "Ignoring %s\n", if_name);
                        return;
                    } else
                        li = multi_link_create_new_link(if_name, 
                                li_static->metric);
                } else {
                    /* Allocate a new link, add to list and start DHCP */
                    li = multi_link_create_new_link(if_name, 0);
                }

                if (!li) {
                    MULTI_DEBUG_PRINT_SYSLOG(stderr, "Could not create link\n");
                    return;
                }
                
                //Insert link into link list
                LIST_INSERT_HEAD(&multi_link_links_2, li, next);
                ++multi_link_num_links;

                /* Add as a case here! The check for point to point  */
                if(li_static != NULL && li_static->proto == PROTO_STATIC){
					MULTI_DEBUG_PRINT_SYSLOG(stderr, "Link %s found in static list\n", 
                            if_name);
                    li->state = GOT_IP_STATIC;
					li->cfg = li_static->cfg_static;
				} else if (ifi->ifi_type == ARPHRD_PPP){
                    /* PPP will be dealt with separatley, since they get the IP
                     * remotely by themself */
                    MULTI_DEBUG_PRINT_SYSLOG(stderr, "Link %s (%u) is PPP! state "
                            "%u %u\n", if_name, ifi->ifi_index, iface_state, 
                            IFF_RUNNING);
                    li->state = LINK_DOWN_PPP;
                    multi_link_get_iface_info(li);

                    if(li->state != GOT_IP_PPP){
                        //Need to treat this in a special way! Remove li, keep
                        //li and have some sort of timeout?
                        MULTI_DEBUG_PRINT_SYSLOG(stderr, "Could not get info for PPP "
                                "link %u (first look)!\n", ifi->ifi_index);
                    } else {
                        //Clean the information that is automatically added to
                        //routing table
                        multi_link_remove_ppp(li);
                    }

                } else if(wireless_mode){ 
                    MULTI_DEBUG_PRINT_SYSLOG(stderr, "Link %s is wlan access point\n",
                            if_name);
                    li->state = LINK_DOWN_AP;
                    multi_link_get_iface_info(li);

                    //Remove the automatic route
                    multi_link_remove_ap(li);
                } else {
					pthread_attr_init(&detach_attr);
					pthread_attr_setdetachstate(&detach_attr, 
                            PTHREAD_CREATE_DETACHED);
					pthread_create(&(li->dhcp_thread), &detach_attr, 
                            multi_dhcp_main, (void *) li);
				}
            } else
                MULTI_DEBUG_PRINT_SYSLOG(stderr, "Limit reached, cannot add more links\n");
        } else if(ifi->ifi_flags & IFF_UP){ //Might replace with IF_OPER_DOWN
            //Check if interface has already been seen
            LIST_FIND_CUSTOM(li, &multi_link_links_2, next, &(ifi->ifi_index),
                    multi_cmp_ifidx);

            //Interface is already seen as UP, so clean up, no matter if static
            //or not. Static is a special case: remove routes, li from list
            //and free li
            if(li != NULL){
                //Need a generic cleanup, move the next "else" into a separate
                //function
                MULTI_DEBUG_PRINT_SYSLOG(stderr,"Interface %s (idx %u) has already "
                    "been seen as UP, will clean\n", if_name, ifi->ifi_index);
                multi_link_delete_link(li, probe_pipe);
                return;
            }

            //Check if interface is in static list
            TAILQ_FIND_CUSTOM(li_static, &multi_shared_static_links, list_ptr, 
                    if_name, multi_cmp_devname);

            if(li_static != NULL && li_static->proto == PROTO_STATIC){
                //Allocate a new link
                MULTI_DEBUG_PRINT_SYSLOG(stderr, "Link %s is UP\n", if_name);
                li = multi_link_create_new_link(if_name, li_static->metric);

                if (li == NULL) {
                    MULTI_DEBUG_PRINT_SYSLOG(stderr, "Failed to create new link\n");
                    return;
                }

                li->state = GOT_IP_STATIC_UP;
                li->cfg = li_static->cfg_static;
                LIST_INSERT_HEAD(&multi_link_links_2, li, next);
                ++multi_link_num_links;
            }
        } else {
            uint32_t dev_idx = ifi->ifi_index;
            LIST_FIND_CUSTOM(li, &multi_link_links_2, next, &dev_idx,
                    multi_cmp_ifidx);

            MULTI_DEBUG_PRINT_SYSLOG(stderr, "Interface %s (index %u) is down, "
                "length %u\n", if_name, ifi->ifi_index, 
                multi_link_num_links);

            if(li == NULL){
                MULTI_DEBUG_PRINT_SYSLOG(stderr, "Could not find %s (index %u), "
                    "length %u\n", if_name, ifi->ifi_index, 
                    multi_link_num_links);
            } else{
                multi_link_delete_link(li, probe_pipe);
            }
        }
    }
}
Ejemplo n.º 2
0
void multi_test_visible_loop(struct multi_config *mc){
    uint8_t buf[MAX_BUFSIZE];
    int32_t retval;
    int32_t i;
    int32_t netlink_sock = 0;
    uint32_t ifi_idx = 0;
    struct iface *ni = NULL;

    /* Needed to create the netlink messages  */
    struct sockaddr_nl src_addr, dest_addr;
    struct iovec iov;
    struct msghdr msg;

    /* Select is used for easier timeouts  */
    fd_set copy, master;
    int32_t fdmax;
    struct timeval tv;

    memset(buf, 0, MAX_BUFSIZE);

    /* Initialise list */
    LIST_INIT(&iface_list);

    /* Define a private constant later! Needs to be set in netlink.h so that the
     * kernel will allow the socket to be created! */
    if((netlink_sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_GENERIC)) < 0){
        perror("Could not create netlink socket: ");
        exit(EXIT_FAILURE);
    }

    /* These are both constant!  */
    memset(&src_addr, 0, sizeof(src_addr));
    memset(&dest_addr, 0, sizeof(dest_addr));
    memset(&msg, 0, sizeof(msg));

    src_addr.nl_family = AF_NETLINK;
    //If PID is set to zero, then the kernel assigns the unique value
    src_addr.nl_pid = 0; 
    //This is the source, it only multicasts, so it does not have to be 
    //member of any groups!
    src_addr.nl_groups = 0; 

    if(bind(netlink_sock, (struct sockaddr *) &src_addr, sizeof(src_addr)) < 0){
        perror("Could not bind netlink socket: ");
        exit(EXIT_FAILURE);
    }

    dest_addr.nl_family = AF_NETLINK;
    dest_addr.nl_pid = 0; 
    dest_addr.nl_groups = 1;

    MULTI_DEBUG_PRINT(stderr, "Multi manager is ready! Netlink socket %d\n", 
            netlink_sock);
    MULTI_DEBUG_PRINT(stderr, "M S\n");

    //Look at the Wikipedia site for iovec and man(7) netlink for examples on
    //how to properly parse netlink and have multiple iovec-entries
    msg.msg_name = (void *) &dest_addr; //This is the message's destination
    msg.msg_namelen = sizeof(dest_addr);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1; 

    //Initialise everything related to select
    FD_ZERO(&master);
    FD_ZERO(&copy);
    FD_SET(mc->socket_pipe[0], &master);
    fdmax = mc->socket_pipe[0];
    tv.tv_sec = 30;
    tv.tv_usec = 0;

    pthread_t multi_thread = multi_start(mc);

    while(1){
        copy = master;
        retval = select(fdmax + 1, &copy, NULL, NULL, &tv);

        //Repeat every UP message
        if(retval == 0){
            for(ni = iface_list.lh_first; ni != NULL; ni = ni->next.le_next){
                printf("Hei\n");
                iov.iov_base = (void *) ni->nlmsg;
                iov.iov_len = ni->nlmsg->nlmsg_len;
                sendmsg(netlink_sock, &msg, 0);
            }

            tv.tv_sec = 30;
            tv.tv_usec = 0;
            continue;
        }

        memset(buf, 0, MAX_BUFSIZE);

        //Sufficient to just memcpy this one and broadcast the netlink message
        retval = read(mc->socket_pipe[0], buf, MAX_BUFSIZE);

        if(retval == -1)
            perror("Failed to read from pipe");
        else {
            memcpy(&ifi_idx, (buf+1), sizeof(uint32_t));
           
            //This check needs to be performed irrespective of if link goes up
            //or down.
            LIST_FIND_CUSTOM(ni, &iface_list, next, &ifi_idx,
                        multi_mc_cmp_ifi);

            if(buf[0] == LINK_UP){
                //Sanity check. If the interface is already found, ignore the
                //announcement from MULTI.
                if(ni)
                    continue;

                //Create a new iface, buffer the up message and add to list
                ni = (struct iface*) malloc(sizeof(struct iface));
                ni->ifi_idx = ifi_idx;
                ni->nlmsg = (struct nlmsghdr *) malloc(NLMSG_SPACE(retval));
                memset(ni->nlmsg, 0, NLMSG_SPACE(retval));
                ni->nlmsg->nlmsg_pid = getpid();
                ni->nlmsg->nlmsg_flags = 0;
                ni->nlmsg->nlmsg_len = NLMSG_SPACE(retval);
                memcpy(NLMSG_DATA(ni->nlmsg), buf, retval);
                LIST_INSERT_HEAD(&iface_list, ni, next);

                //Adjust the base pointer of the message and broadcast message
                iov.iov_base = (void *) ni->nlmsg;
                iov.iov_len = ni->nlmsg->nlmsg_len;
                retval = sendmsg(netlink_sock, &msg, 0);
                MULTI_DEBUG_PRINT(stderr,"Broadcasted %d bytes about an UP "
                        "change in network state\n", retval);
            } else {
                if(ni){
                    //Forward message from MULTI
                    ni->nlmsg->nlmsg_len = NLMSG_SPACE(retval);
                    memcpy(NLMSG_DATA(ni->nlmsg), buf, retval);
                    iov.iov_base = (void *) ni->nlmsg;
                    iov.iov_len = ni->nlmsg->nlmsg_len;
                    retval = sendmsg(netlink_sock, &msg, 0);
                    MULTI_DEBUG_PRINT(stderr,"Broadcasted %d bytes about a "
                            "DOWN change in network state\n", retval);
                    
                    LIST_REMOVE(ni, next);
                    free(ni);
                }
            }
        }
    }
}