int up_interface(struct interface *iface) { if_up(iface->ifp); return 0; }
/* * Process an ioctl request. */ int loioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct ifreq *ifr; int error = 0; switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_RUNNING; if_up(ifp); /* send up RTM_IFINFO */ /* * Everything else is done at a higher level. */ break; case SIOCADDMULTI: case SIOCDELMULTI: break; case SIOCSIFMTU: ifr = (struct ifreq *)data; ifp->if_mtu = ifr->ifr_mtu; break; default: error = ENOTTY; } return (error); }
/* thread reading entries form others babel daemons */ static int babel_read_protocol (struct thread *thread) { int rc; struct interface *ifp = NULL; struct sockaddr_in6 sin6; struct listnode *linklist_node = NULL; assert(babel_routing_process != NULL); assert(protocol_socket >= 0); rc = babel_recv(protocol_socket, receive_buffer, receive_buffer_size, (struct sockaddr*)&sin6, sizeof(sin6)); if(rc < 0) { if(errno != EAGAIN && errno != EINTR) { zlog_err("recv: %s", safe_strerror(errno)); } } else { FOR_ALL_INTERFACES(ifp, linklist_node) { if(!if_up(ifp)) continue; if(ifp->ifindex == sin6.sin6_scope_id) { parse_packet((unsigned char*)&sin6.sin6_addr, ifp, receive_buffer, rc); break; } } } /* re-add thread */ babel_routing_process->t_read = thread_add_read(master, &babel_read_protocol, NULL, protocol_socket); return 0; }
static void force_reup() { int i; for(i=0; i < Num_pseudo; i++) { if ( _rif_ip_s(My) == _rif_ip_s(Allocation_table[i]) ) { /* This is ours */ int ic, n=0; struct interface iface, *nif; entry *VE; VE = &Allocation_table[i]; for(nif=&VE->pseudo_if; n<MAX_DEP_IF; nif = &(VE->extra_ifs[n++])) { if(nif->ipaddr.s_addr == 0) break; memcpy(&iface, nif, sizeof(struct interface)); ic = if_up(&iface); if(ic) wack_alarm(PRINT, "%s", if_error()); else { char buffer[16]; snprintf(buffer, 16, inet_ntoa(iface.ipaddr)); wack_alarm(PRINT, " (re)UP: %s:%s/%s", iface.ifname,buffer,inet_ntoa(iface.netmask)); } } invoke_spoofer(VE); } } }
void usbpf_attach(struct usb_bus *ubus) { struct ifnet *ifp; if (usb_no_pf != 0) { ubus->ifp = NULL; return; } ifp = ubus->ifp = if_alloc(IFT_USB); if (ifp == NULL) { device_printf(ubus->parent, "usbpf: Could not allocate " "instance\n"); return; } if_initname(ifp, "usbus", device_get_unit(ubus->bdev)); ifp->if_flags = IFF_CANTCONFIG; if_attach(ifp); if_up(ifp); /* * XXX According to the specification of DLT_USB, it indicates * packets beginning with USB setup header. But not sure all * packets would be. */ bpfattach(ifp, DLT_USB, USBPF_HDR_LEN); if (bootverbose) device_printf(ubus->parent, "usbpf: Attached\n"); }
void check_interfaces(void) { struct interface *ifp; int rc, ifindex_changed = 0; unsigned int ifindex; FOR_ALL_INTERFACES(ifp) { ifindex = if_nametoindex(ifp->name); if(ifindex != ifp->ifindex) { debugf("Noticed ifindex change for %s.\n", ifp->name); ifp->ifindex = 0; interface_up(ifp, 0); ifp->ifindex = ifindex; ifindex_changed = 1; } if(ifp->ifindex > 0) rc = kernel_interface_operational(ifp->name, ifp->ifindex); else rc = 0; if((rc > 0) != if_up(ifp)) { debugf("Noticed status change for %s.\n", ifp->name); interface_up(ifp, rc > 0); } if(if_up(ifp)) { /* Bother, said Pooh. We should probably check for a change in IPv4 addresses at this point. */ check_link_local_addresses(ifp); check_interface_channel(ifp); rc = check_interface_ipv4(ifp); if(rc > 0) { send_request(ifp, NULL, 0, NULL, 0); send_update(ifp, 0, NULL, 0, NULL, 0); } } } if(ifindex_changed) renumber_filters(); }
int interface_ll_address(struct interface *ifp, const unsigned char *address) { int i; if(!if_up(ifp)) return 0; for(i = 0; i < ifp->numll; i++) if(memcmp(ifp->ll[i], address, 16) == 0) return 1; return 0; }
/* function: configure_tun_ip * configures the ipv4 and ipv6 addresses on the tunnel interface * tunnel - tun device data */ void configure_tun_ip(const struct tun_data *tunnel) { int status; // Configure the interface before bringing it up. As soon as we bring the interface up, the // framework will be notified and will assume the interface's configuration has been finalized. status = add_address(tunnel->device4, AF_INET, &Global_Clatd_Config.ipv4_local_subnet, 32, &Global_Clatd_Config.ipv4_local_subnet); if(status < 0) { logmsg(ANDROID_LOG_FATAL,"configure_tun_ip/if_address(4) failed: %s",strerror(-status)); exit(1); } if((status = if_up(tunnel->device6, Global_Clatd_Config.mtu)) < 0) { logmsg(ANDROID_LOG_FATAL,"configure_tun_ip/if_up(6) failed: %s",strerror(-status)); exit(1); } if((status = if_up(tunnel->device4, Global_Clatd_Config.ipv4mtu)) < 0) { logmsg(ANDROID_LOG_FATAL,"configure_tun_ip/if_up(4) failed: %s",strerror(-status)); exit(1); } configure_tun_ipv6(tunnel); }
void if_refresh (struct interface *ifp) { if (if_is_up (ifp)) { if_get_flags (ifp); if (! if_is_up (ifp)) if_down (ifp); } else { if_get_flags (ifp); if (if_is_up (ifp)) if_up (ifp); } }
void if_refresh (struct interface_FOO *ifp) { if (if_is_operative (ifp)) { if_get_flags (ifp); if (! if_is_operative (ifp)) if_down (ifp); } else { if_get_flags (ifp); if (if_is_operative (ifp)) if_up (ifp); } }
/* set link_status */ void set_link_status(int link_status) { wd_status.info_updated |= WDS_LINK_STATUS; if (wd_status.link_status == link_status) return; if (wd_status.link_status < 2 && link_status == 2) { if_up(); } if (wd_status.link_status == 2 && link_status < 2) { if_down(); } if (link_status == 1) { first_nego_flag = 1; } wd_status.link_status = link_status; }
/* Update the flags field of the ifp with the new flag set provided. * Take whatever actions are required for any changes in flags we care * about. * * newflags should be the raw value, as obtained from the OS. */ void if_flags_update (struct interface *ifp, uint64_t newflags) { if_flags_mangle (ifp, &newflags); if (if_is_operative (ifp)) { /* operative -> inoperative? */ ifp->flags = newflags; if (!if_is_operative (ifp)) if_down (ifp); } else { /* inoperative -> operative? */ ifp->flags = newflags; if (if_is_operative (ifp)) if_up (ifp); } }
static void Acquire( entry *VE ) { int ic, n=0; struct interface iface, *nif; for(nif=&VE->pseudo_if; n<MAX_DEP_IF; nif = &(VE->extra_ifs[n++])) { if(nif->ipaddr.s_addr == 0) break; memcpy(&iface, nif, sizeof(struct interface)); ic = if_up(&iface); if(ic) wack_alarm(PRINT, "%d %s", __LINE__, if_error()); else { char buffer[16]; snprintf(buffer, 16, inet_ntoa(iface.ipaddr)); wack_alarm(PRINT, " UP: %s:%s/%s", iface.ifname,buffer,inet_ntoa(iface.netmask)); } } invoke_spoofer(VE); execute_all_user(VE->pseudo_if, VE->extra_ifs, VE->real_if, DLFUNCS_TYPE_ON_UP); My.num_allocated++; }
static void local_notify_interface_1(struct local_socket *s, struct interface *ifp, int kind) { char buf[512], v4[INET_ADDRSTRLEN]; int rc; int up; up = if_up(ifp); if(up && ifp->ipv4) inet_ntop(AF_INET, ifp->ipv4, v4, INET_ADDRSTRLEN); else v4[0] = '\0'; if(up) rc = snprintf(buf, 512, "%s interface %s up true%s%s%s%s\n", local_kind(kind), ifp->name, ifp->ll ? " ipv6 " : "", ifp->ll ? format_address(*ifp->ll) : "", v4[0] ? " ipv4 " : "", v4); else rc = snprintf(buf, 512, "%s interface %s up false\n", local_kind(kind), ifp->name); if(rc < 0 || rc >= 512) goto fail; rc = write_timeout(s->fd, buf, rc); if(rc < 0) goto fail; return; fail: shutdown(s->fd, 1); return; }
static int netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h) { int len; struct ifinfomsg *ifi; struct rtattr *tb[IFLA_MAX + 1]; struct interface *ifp; char *name; ifi = NLMSG_DATA (h); if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)) { /* If this is not link add/delete message so print warning. */ zlog_warn ("netlink_link_change: wrong kernel message %d\n", h->nlmsg_type); return 0; } len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg)); if (len < 0) return -1; /* Looking up interface name. */ memset (tb, 0, sizeof tb); netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len); #ifdef IFLA_WIRELESS /* check for wireless messages to ignore */ if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0)) { if (IS_DEBUG_HA(kroute, KROUTE)) zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__); return 0; } #endif /* IFLA_WIRELESS */ if (tb[IFLA_IFNAME] == NULL) return -1; name = (char *) RTA_DATA (tb[IFLA_IFNAME]); /* Add interface. */ if (h->nlmsg_type == RTM_NEWLINK) { ifp = if_lookup_by_name (name); if (ifp == NULL || !CHECK_FLAG (ifp->status, KROUTE_INTERFACE_ACTIVE)) { if (ifp == NULL) ifp = if_get_by_name (name); set_ifindex(ifp, ifi->ifi_index); ifp->flags = ifi->ifi_flags & 0x0000fffff; ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]); ifp->metric = 1; netlink_interface_update_hw_addr (tb, ifp); /* If new link is added. */ if_add_update (ifp); } else { /* Interface status change. */ set_ifindex(ifp, ifi->ifi_index); ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]); ifp->metric = 1; netlink_interface_update_hw_addr (tb, ifp); if (if_is_operative (ifp)) { ifp->flags = ifi->ifi_flags & 0x0000fffff; if (!if_is_operative (ifp)) if_down (ifp); else /* Must notify client daemons of new interface status. */ kroute_interface_up_update (ifp); } else { ifp->flags = ifi->ifi_flags & 0x0000fffff; if (if_is_operative (ifp)) if_up (ifp); } } } else { /* RTM_DELLINK. */ ifp = if_lookup_by_name (name); if (ifp == NULL) { zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find", name); return 0; } if_delete_update (ifp); } return 0; }
int netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h) { int len; struct ifinfomsg *ifi; struct rtattr *tb [IFLA_MAX + 1]; struct interface *ifp; char *name; ifi = NLMSG_DATA (h); if (! (h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)) { /* If this is not link add/delete message so print warning. */ zlog_warn ("netlink_link_change: wrong kernel message %d\n", h->nlmsg_type); return 0; } len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ifinfomsg)); if (len < 0) return -1; /* Looking up interface name. */ memset (tb, 0, sizeof tb); netlink_parse_rtattr (tb, IFLA_MAX, IFLA_RTA (ifi), len); if (tb[IFLA_IFNAME] == NULL) return -1; name = (char *)RTA_DATA(tb[IFLA_IFNAME]); /* Add interface. */ if (h->nlmsg_type == RTM_NEWLINK) { ifp = if_lookup_by_name (name); if (ifp == NULL || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) { if (ifp == NULL) ifp = if_get_by_name (name); ifp->ifindex = ifi->ifi_index; ifp->flags = ifi->ifi_flags & 0x0000fffff; ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]); ifp->metric = 1; /* If new link is added. */ if_add_update(ifp); } else { /* Interface status change. */ ifp->ifindex = ifi->ifi_index; ifp->mtu = *(int *)RTA_DATA (tb[IFLA_MTU]); ifp->metric = 1; if (if_is_up (ifp)) { ifp->flags = ifi->ifi_flags & 0x0000fffff; if (! if_is_up (ifp)) if_down (ifp); } else { ifp->flags = ifi->ifi_flags & 0x0000fffff; if (if_is_up (ifp)) if_up (ifp); } } } else { /* RTM_DELLINK. */ ifp = if_lookup_by_name (name); if (ifp == NULL) { zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find", ifp->name); return 0; } if_delete_update (ifp); } return 0; }
int main(int argc, char **argv) { struct sockaddr_in6 sin6; int rc, fd, i, opt; time_t expiry_time, source_expiry_time, kernel_dump_time; const char **config_files = NULL; int num_config_files = 0; void *vrc; unsigned int seed; struct interface *ifp; gettime(&now); rc = read_random_bytes(&seed, sizeof(seed)); if(rc < 0) { perror("read(random)"); seed = 42; } seed ^= (now.tv_sec ^ now.tv_usec); srandom(seed); parse_address("ff02:0:0:0:0:0:1:6", protocol_group, NULL); protocol_port = 6696; change_smoothing_half_life(4); has_ipv6_subtrees = kernel_has_ipv6_subtrees(); while(1) { opt = getopt(argc, argv, "m:p:h:H:i:k:A:sruS:d:g:G:lwz:M:t:T:c:C:DL:I:V"); if(opt < 0) break; switch(opt) { case 'm': rc = parse_address(optarg, protocol_group, NULL); if(rc < 0) goto usage; if(protocol_group[0] != 0xff) { fprintf(stderr, "%s is not a multicast address\n", optarg); goto usage; } if(protocol_group[1] != 2) { fprintf(stderr, "Warning: %s is not a link-local multicast address\n", optarg); } break; case 'p': protocol_port = parse_nat(optarg); if(protocol_port <= 0 || protocol_port > 0xFFFF) goto usage; break; case 'h': default_wireless_hello_interval = parse_thousands(optarg); if(default_wireless_hello_interval <= 0 || default_wireless_hello_interval > 0xFFFF * 10) goto usage; break; case 'H': default_wired_hello_interval = parse_thousands(optarg); if(default_wired_hello_interval <= 0 || default_wired_hello_interval > 0xFFFF * 10) goto usage; break; case 'k': kernel_metric = parse_nat(optarg); if(kernel_metric < 0 || kernel_metric > 0xFFFF) goto usage; break; case 'A': allow_duplicates = parse_nat(optarg); if(allow_duplicates < 0 || allow_duplicates > 0xFFFF) goto usage; break; case 's': split_horizon = 0; break; case 'r': random_id = 1; break; case 'u': keep_unfeasible = 1; break; case 'S': state_file = optarg; break; case 'd': debug = parse_nat(optarg); if(debug < 0) goto usage; break; case 'g': case 'G': if(opt == 'g') local_server_write = 0; else local_server_write = 1; if(optarg[0] == '/') { local_server_port = -1; free(local_server_path); local_server_path = strdup(optarg); } else { local_server_port = parse_nat(optarg); free(local_server_path); local_server_path = NULL; if(local_server_port <= 0 || local_server_port > 0xFFFF) goto usage; } break; case 'l': link_detect = 1; break; case 'w': all_wireless = 1; break; case 'z': { char *comma; diversity_kind = (int)strtol(optarg, &comma, 0); if(*comma == '\0') diversity_factor = 128; else if(*comma == ',') diversity_factor = parse_nat(comma + 1); else goto usage; if(diversity_factor <= 0 || diversity_factor > 256) goto usage; } break; case 'M': { int l = parse_nat(optarg); if(l < 0 || l > 3600) goto usage; change_smoothing_half_life(l); break; } case 't': export_table = parse_nat(optarg); if(export_table < 0 || export_table > 0xFFFF) goto usage; break; case 'T': if(add_import_table(parse_nat(optarg))) goto usage; break; case 'c': config_files = realloc(config_files, (num_config_files + 1) * sizeof(char*)); if(config_files == NULL) { fprintf(stderr, "Couldn't allocate config file.\n"); exit(1); } config_files[num_config_files++] = optarg; break; case 'C': rc = parse_config_from_string(optarg, strlen(optarg), NULL); if(rc != CONFIG_ACTION_DONE) { fprintf(stderr, "Couldn't parse configuration from command line.\n"); exit(1); } break; case 'D': do_daemonise = 1; break; case 'L': logfile = optarg; break; case 'I': pidfile = optarg; break; case 'V': fprintf(stderr, "%s\n", BABELD_VERSION); exit(0); break; default: goto usage; } } if(num_config_files == 0) { if(access("/etc/babeld.conf", F_OK) >= 0) { config_files = malloc(sizeof(char*)); if(config_files == NULL) { fprintf(stderr, "Couldn't allocate config file.\n"); exit(1); } config_files[num_config_files++] = "/etc/babeld.conf"; } } for(i = 0; i < num_config_files; i++) { int line; rc = parse_config_from_file(config_files[i], &line); if(rc < 0) { fprintf(stderr, "Couldn't parse configuration from file %s " "(error at line %d).\n", config_files[i], line); exit(1); } } free(config_files); if(default_wireless_hello_interval <= 0) default_wireless_hello_interval = 4000; default_wireless_hello_interval = MAX(default_wireless_hello_interval, 5); if(default_wired_hello_interval <= 0) default_wired_hello_interval = 4000; default_wired_hello_interval = MAX(default_wired_hello_interval, 5); resend_delay = 2000; resend_delay = MIN(resend_delay, default_wireless_hello_interval / 2); resend_delay = MIN(resend_delay, default_wired_hello_interval / 2); resend_delay = MAX(resend_delay, 20); if(do_daemonise) { if(logfile == NULL) logfile = "/var/log/babeld.log"; } rc = reopen_logfile(); if(rc < 0) { perror("reopen_logfile()"); exit(1); } fd = open("/dev/null", O_RDONLY); if(fd < 0) { perror("open(null)"); exit(1); } rc = dup2(fd, 0); if(rc < 0) { perror("dup2(null, 0)"); exit(1); } close(fd); if(do_daemonise) { rc = daemonise(); if(rc < 0) { perror("daemonise"); exit(1); } } if(pidfile && pidfile[0] != '\0') { int pfd, len; char buf[100]; len = snprintf(buf, 100, "%lu", (unsigned long)getpid()); if(len < 0 || len >= 100) { perror("snprintf(getpid)"); exit(1); } pfd = open(pidfile, O_WRONLY | O_CREAT | O_EXCL, 0644); if(pfd < 0) { char buf[40]; snprintf(buf, 40, "creat(%s)", pidfile); buf[39] = '\0'; perror(buf); exit(1); } rc = write(pfd, buf, len); if(rc < len) { perror("write(pidfile)"); goto fail_pid; } close(pfd); } rc = kernel_setup(1); if(rc < 0) { fprintf(stderr, "kernel_setup failed.\n"); goto fail_pid; } rc = kernel_setup_socket(1); if(rc < 0) { fprintf(stderr, "kernel_setup_socket failed.\n"); kernel_setup(0); goto fail_pid; } rc = finalise_config(); if(rc < 0) { fprintf(stderr, "Couldn't finalise configuration.\n"); goto fail; } for(i = optind; i < argc; i++) { vrc = add_interface(argv[i], NULL); if(vrc == NULL) goto fail; } if(interfaces == NULL) { fprintf(stderr, "Eek... asked to run on no interfaces!\n"); goto fail; } if(!have_id && !random_id) { /* We use all available interfaces here, since this increases the chances of getting a stable router-id in case the set of Babel interfaces changes. */ for(i = 1; i < 256; i++) { char buf[IF_NAMESIZE], *ifname; unsigned char eui[8]; ifname = if_indextoname(i, buf); if(ifname == NULL) continue; rc = if_eui64(ifname, i, eui); if(rc < 0) continue; memcpy(myid, eui, 8); have_id = 1; break; } } if(!have_id) { if(!random_id) fprintf(stderr, "Warning: couldn't find router id -- " "using random value.\n"); rc = read_random_bytes(myid, 8); if(rc < 0) { perror("read(random)"); goto fail; } /* Clear group and global bits */ myid[0] &= ~3; } myseqno = (random() & 0xFFFF); fd = open(state_file, O_RDONLY); if(fd < 0 && errno != ENOENT) perror("open(babel-state)"); rc = unlink(state_file); if(fd >= 0 && rc < 0) { perror("unlink(babel-state)"); /* If we couldn't unlink it, it's probably stale. */ close(fd); fd = -1; } if(fd >= 0) { char buf[100]; int s; rc = read(fd, buf, 99); if(rc < 0) { perror("read(babel-state)"); } else { buf[rc] = '\0'; rc = sscanf(buf, "%d\n", &s); if(rc == 1 && s >= 0 && s <= 0xFFFF) { myseqno = seqno_plus(s, 1); } else { fprintf(stderr, "Couldn't parse babel-state.\n"); } } close(fd); fd = -1; } protocol_socket = babel_socket(protocol_port); if(protocol_socket < 0) { perror("Couldn't create link local socket"); goto fail; } if(local_server_port >= 0) { local_server_socket = tcp_server_socket(local_server_port, 1); if(local_server_socket < 0) { perror("local_server_socket"); goto fail; } } else if(local_server_path) { local_server_socket = unix_server_socket(local_server_path); if(local_server_socket < 0) { perror("local_server_socket"); goto fail; } } init_signals(); rc = resize_receive_buffer(1500); if(rc < 0) goto fail; if(receive_buffer == NULL) goto fail; check_interfaces(); rc = check_xroutes(0); if(rc < 0) fprintf(stderr, "Warning: couldn't check exported routes.\n"); rc = check_rules(); if(rc < 0) fprintf(stderr, "Warning: couldn't check rules.\n"); kernel_routes_changed = 0; kernel_rules_changed = 0; kernel_link_changed = 0; kernel_addr_changed = 0; kernel_dump_time = now.tv_sec + roughly(30); schedule_neighbours_check(5000, 1); schedule_interfaces_check(30000, 1); expiry_time = now.tv_sec + roughly(30); source_expiry_time = now.tv_sec + roughly(300); /* Make some noise so that others notice us, and send retractions in case we were restarted recently */ FOR_ALL_INTERFACES(ifp) { if(!if_up(ifp)) continue; /* Apply jitter before we send the first message. */ usleep(roughly(10000)); gettime(&now); send_hello(ifp); send_wildcard_retraction(ifp); } FOR_ALL_INTERFACES(ifp) { if(!if_up(ifp)) continue; usleep(roughly(10000)); gettime(&now); send_hello(ifp); send_wildcard_retraction(ifp); send_self_update(ifp); send_request(ifp, NULL, 0, NULL, 0); flushupdates(ifp); flushbuf(ifp); } debugf("Entering main loop.\n"); while(1) { struct timeval tv; fd_set readfds; gettime(&now); tv = check_neighbours_timeout; timeval_min(&tv, &check_interfaces_timeout); timeval_min_sec(&tv, expiry_time); timeval_min_sec(&tv, source_expiry_time); timeval_min_sec(&tv, kernel_dump_time); timeval_min(&tv, &resend_time); FOR_ALL_INTERFACES(ifp) { if(!if_up(ifp)) continue; timeval_min(&tv, &ifp->flush_timeout); timeval_min(&tv, &ifp->hello_timeout); timeval_min(&tv, &ifp->update_timeout); timeval_min(&tv, &ifp->update_flush_timeout); } timeval_min(&tv, &unicast_flush_timeout); FD_ZERO(&readfds); if(timeval_compare(&tv, &now) > 0) { int maxfd = 0; timeval_minus(&tv, &tv, &now); FD_SET(protocol_socket, &readfds); maxfd = MAX(maxfd, protocol_socket); if(kernel_socket < 0) kernel_setup_socket(1); if(kernel_socket >= 0) { FD_SET(kernel_socket, &readfds); maxfd = MAX(maxfd, kernel_socket); } if(local_server_socket >= 0 && num_local_sockets < MAX_LOCAL_SOCKETS) { FD_SET(local_server_socket, &readfds); maxfd = MAX(maxfd, local_server_socket); } for(i = 0; i < num_local_sockets; i++) { FD_SET(local_sockets[i].fd, &readfds); maxfd = MAX(maxfd, local_sockets[i].fd); } rc = select(maxfd + 1, &readfds, NULL, NULL, &tv); if(rc < 0) { if(errno != EINTR) { perror("select"); sleep(1); } rc = 0; FD_ZERO(&readfds); } } gettime(&now); if(exiting) break; if(kernel_socket >= 0 && FD_ISSET(kernel_socket, &readfds)) { struct kernel_filter filter = {0}; filter.route = kernel_route_notify; filter.addr = kernel_addr_notify; filter.link = kernel_link_notify; filter.rule = kernel_rule_notify; kernel_callback(&filter); } if(FD_ISSET(protocol_socket, &readfds)) { rc = babel_recv(protocol_socket, receive_buffer, receive_buffer_size, (struct sockaddr*)&sin6, sizeof(sin6)); if(rc < 0) { if(errno != EAGAIN && errno != EINTR) { perror("recv"); sleep(1); } } else { FOR_ALL_INTERFACES(ifp) { if(!if_up(ifp)) continue; if(ifp->ifindex == sin6.sin6_scope_id) { parse_packet((unsigned char*)&sin6.sin6_addr, ifp, receive_buffer, rc); VALGRIND_MAKE_MEM_UNDEFINED(receive_buffer, receive_buffer_size); break; } } } } if(local_server_socket >= 0 && FD_ISSET(local_server_socket, &readfds)) accept_local_connections(); i = 0; while(i < num_local_sockets) { if(FD_ISSET(local_sockets[i].fd, &readfds)) { rc = local_read(&local_sockets[i]); if(rc <= 0) { if(rc < 0) { if(errno == EINTR || errno == EAGAIN) continue; perror("read(local_socket)"); } local_socket_destroy(i); } } i++; } if(reopening) { kernel_dump_time = now.tv_sec; check_neighbours_timeout = now; expiry_time = now.tv_sec; rc = reopen_logfile(); if(rc < 0) { perror("reopen_logfile"); break; } reopening = 0; } if(kernel_link_changed || kernel_addr_changed) { check_interfaces(); kernel_link_changed = 0; } if(kernel_routes_changed || kernel_addr_changed || kernel_rules_changed || now.tv_sec >= kernel_dump_time) { rc = check_xroutes(1); if(rc < 0) fprintf(stderr, "Warning: couldn't check exported routes.\n"); rc = check_rules(); if(rc < 0) fprintf(stderr, "Warning: couldn't check rules.\n"); kernel_routes_changed = kernel_rules_changed = kernel_addr_changed = 0; if(kernel_socket >= 0) kernel_dump_time = now.tv_sec + roughly(300); else kernel_dump_time = now.tv_sec + roughly(30); } if(timeval_compare(&check_neighbours_timeout, &now) < 0) { int msecs; msecs = check_neighbours(); /* Multiply by 3/2 to allow neighbours to expire. */ msecs = MAX(3 * msecs / 2, 10); schedule_neighbours_check(msecs, 1); } if(timeval_compare(&check_interfaces_timeout, &now) < 0) { check_interfaces(); schedule_interfaces_check(30000, 1); } if(now.tv_sec >= expiry_time) { expire_routes(); expire_resend(); expiry_time = now.tv_sec + roughly(30); } if(now.tv_sec >= source_expiry_time) { expire_sources(); source_expiry_time = now.tv_sec + roughly(300); } FOR_ALL_INTERFACES(ifp) { if(!if_up(ifp)) continue; if(timeval_compare(&now, &ifp->hello_timeout) >= 0) send_hello(ifp); if(timeval_compare(&now, &ifp->update_timeout) >= 0) send_update(ifp, 0, NULL, 0, NULL, 0); if(timeval_compare(&now, &ifp->update_flush_timeout) >= 0) flushupdates(ifp); } if(resend_time.tv_sec != 0) { if(timeval_compare(&now, &resend_time) >= 0) do_resend(); } if(unicast_flush_timeout.tv_sec != 0) { if(timeval_compare(&now, &unicast_flush_timeout) >= 0) flush_unicast(1); } FOR_ALL_INTERFACES(ifp) { if(!if_up(ifp)) continue; if(ifp->flush_timeout.tv_sec != 0) { if(timeval_compare(&now, &ifp->flush_timeout) >= 0) flushbuf(ifp); } } if(UNLIKELY(debug || dumping)) { dump_tables(stdout); dumping = 0; } }
int interface_up(struct interface *ifp, int up) { int mtu, rc, wired; struct ipv6_mreq mreq; if((!!up) == if_up(ifp)) return 0; if(up) ifp->flags |= IF_UP; else ifp->flags &= ~IF_UP; if(up) { if(ifp->ifindex <= 0) { fprintf(stderr, "Upping unknown interface %s.\n", ifp->name); goto fail; } rc = kernel_setup_interface(1, ifp->name, ifp->ifindex); if(rc < 0) { fprintf(stderr, "kernel_setup_interface(%s, %d) failed.\n", ifp->name, ifp->ifindex); goto fail; } mtu = kernel_interface_mtu(ifp->name, ifp->ifindex); if(mtu < 0) { fprintf(stderr, "Warning: couldn't get MTU of interface %s (%d).\n", ifp->name, ifp->ifindex); mtu = 1280; } /* We need to be able to fit at least two messages into a packet, so MTUs below 116 require lower layer fragmentation. */ /* In IPv6, the minimum MTU is 1280, and every host must be able to reassemble up to 1500 bytes, but I'd rather not rely on this. */ if(mtu < 128) { fprintf(stderr, "Suspiciously low MTU %d on interface %s (%d).\n", mtu, ifp->name, ifp->ifindex); mtu = 128; } if(ifp->sendbuf) free(ifp->sendbuf); /* 40 for IPv6 header, 8 for UDP header, 12 for good luck. */ ifp->bufsize = mtu - sizeof(packet_header) - 60; ifp->sendbuf = malloc(ifp->bufsize); if(ifp->sendbuf == NULL) { fprintf(stderr, "Couldn't allocate sendbuf.\n"); ifp->bufsize = 0; goto fail; } rc = resize_receive_buffer(mtu); if(rc < 0) fprintf(stderr, "Warning: couldn't resize " "receive buffer for interface %s (%d) (%d bytes).\n", ifp->name, ifp->ifindex, mtu); if(IF_CONF(ifp, wired) == CONFIG_NO) { wired = 0; } else if(IF_CONF(ifp, wired) == CONFIG_YES) { wired = 1; } else if(all_wireless) { wired = 0; } else { rc = kernel_interface_wireless(ifp->name, ifp->ifindex); if(rc < 0) { fprintf(stderr, "Warning: couldn't determine whether %s (%d) " "is a wireless interface.\n", ifp->name, ifp->ifindex); wired = 0; } else { wired = !rc; } } if(wired) { ifp->flags |= IF_WIRED; ifp->cost = IF_CONF(ifp, cost); if(ifp->cost <= 0) ifp->cost = 96; if(IF_CONF(ifp, split_horizon) == CONFIG_NO) ifp->flags &= ~IF_SPLIT_HORIZON; else if(IF_CONF(ifp, split_horizon) == CONFIG_YES) ifp->flags |= IF_SPLIT_HORIZON; else if(split_horizon) ifp->flags |= IF_SPLIT_HORIZON; else ifp->flags &= ~IF_SPLIT_HORIZON; if(IF_CONF(ifp, lq) == CONFIG_YES) ifp->flags |= IF_LQ; else ifp->flags &= ~IF_LQ; } else { ifp->flags &= ~IF_WIRED; ifp->cost = IF_CONF(ifp, cost); if(ifp->cost <= 0) ifp->cost = 256; if(IF_CONF(ifp, split_horizon) == CONFIG_YES) ifp->flags |= IF_SPLIT_HORIZON; else ifp->flags &= ~IF_SPLIT_HORIZON; if(IF_CONF(ifp, lq) == CONFIG_NO) ifp->flags &= ~IF_LQ; else ifp->flags |= IF_LQ; } if(IF_CONF(ifp, faraway) == CONFIG_YES) ifp->flags |= IF_FARAWAY; if(IF_CONF(ifp, hello_interval) > 0) ifp->hello_interval = IF_CONF(ifp, hello_interval); else if((ifp->flags & IF_WIRED)) ifp->hello_interval = default_wired_hello_interval; else ifp->hello_interval = default_wireless_hello_interval; ifp->update_interval = IF_CONF(ifp, update_interval) > 0 ? IF_CONF(ifp, update_interval) : ifp->hello_interval * 4; ifp->rtt_decay = IF_CONF(ifp, rtt_decay) > 0 ? IF_CONF(ifp, rtt_decay) : 42; ifp->rtt_min = IF_CONF(ifp, rtt_min) > 0 ? IF_CONF(ifp, rtt_min) : 10000; ifp->rtt_max = IF_CONF(ifp, rtt_max) > 0 ? IF_CONF(ifp, rtt_max) : 120000; if(ifp->rtt_max <= ifp->rtt_min) { fprintf(stderr, "Uh, rtt-max is less than or equal to rtt-min (%d <= %d). " "Setting it to %d.\n", ifp->rtt_max, ifp->rtt_min, ifp->rtt_min + 10000); ifp->rtt_max = ifp->rtt_min + 10000; } ifp->max_rtt_penalty = IF_CONF(ifp, max_rtt_penalty); if(IF_CONF(ifp, enable_timestamps) == CONFIG_YES || (IF_CONF(ifp, enable_timestamps) == CONFIG_DEFAULT && ifp->max_rtt_penalty > 0)) ifp->flags |= IF_TIMESTAMPS; rc = check_link_local_addresses(ifp); if(rc < 0) { goto fail; } memset(&mreq, 0, sizeof(mreq)); memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16); mreq.ipv6mr_interface = ifp->ifindex; rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char*)&mreq, sizeof(mreq)); if(rc < 0) { perror("setsockopt(IPV6_JOIN_GROUP)"); goto fail; } check_interface_channel(ifp); update_interface_metric(ifp); rc = check_interface_ipv4(ifp); debugf("Upped interface %s (%s, cost=%d, channel=%d%s).\n", ifp->name, (ifp->flags & IF_WIRED) ? "wired" : "wireless", ifp->cost, ifp->channel, ifp->ipv4 ? ", IPv4" : ""); set_timeout(&ifp->hello_timeout, ifp->hello_interval); set_timeout(&ifp->update_timeout, ifp->update_interval); send_hello(ifp); if(rc > 0) send_update(ifp, 0, NULL, 0, NULL, 0); send_request(ifp, NULL, 0, NULL, 0); } else { flush_interface_routes(ifp, 0); ifp->buffered = 0; ifp->bufsize = 0; free(ifp->sendbuf); ifp->num_buffered_updates = 0; ifp->update_bufsize = 0; if(ifp->buffered_updates) free(ifp->buffered_updates); ifp->buffered_updates = NULL; ifp->sendbuf = NULL; if(ifp->ifindex > 0) { memset(&mreq, 0, sizeof(mreq)); memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16); mreq.ipv6mr_interface = ifp->ifindex; rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char*)&mreq, sizeof(mreq)); if(rc < 0) perror("setsockopt(IPV6_LEAVE_GROUP)"); kernel_setup_interface(0, ifp->name, ifp->ifindex); } if(ifp->ll) free(ifp->ll); ifp->ll = NULL; ifp->numll = 0; } local_notify_interface(ifp, LOCAL_CHANGE); return 1; fail: assert(up); interface_up(ifp, 0); local_notify_interface(ifp, LOCAL_CHANGE); return -1; }
int main (int argc, char *argv[]) { int A,B,C,D, i, ic; struct interface req, myips[300]; int state; #ifdef WIN32 WSADATA wsadata; WSAStartup(WINSOCK_VERSION, &wsadata); #endif i=1; if(argc < 2) goto usage_error; if(argv[i][0] != '-') goto usage_error; switch(argv[i++][1]) { case 'r': state=ARPLIST; break; case 'l': state=LIST; break; case 'a': state=ADD; strcpy(req.ifname, argv[i++]); sscanf(argv[i++], "%d.%d.%d.%d", &A,&B,&C,&D); req.ipaddr.s_addr = htonl((A << 24) | (B << 16) | (C << 8) | D); sscanf(argv[i++], "%d.%d.%d.%d", &A,&B,&C,&D); req.bcast.s_addr = htonl((A << 24) | (B << 16) | (C << 8) | D); sscanf(argv[i++], "%d.%d.%d.%d", &A,&B,&C,&D); req.netmask.s_addr = htonl((A << 24) | (B << 16) | (C << 8) | D); break; case 'd': state=DELETE; sscanf(argv[i++], "%d.%d.%d.%d", &A,&B,&C,&D); req.ifname[0] = '\0'; req.ipaddr.s_addr = htonl((A << 24) | (B << 16) | (C << 8) | D); break; case 's': state=SPOOF; strcpy(req.ifname, argv[i++]); sscanf(argv[i++], "%d.%d.%d.%d", &A,&B,&C,&D); req.ipaddr.s_addr = htonl((A << 24) | (B << 16) | (C << 8) | D); sscanf(argv[i++], "%d.%d.%d.%d", &A,&B,&C,&D); req.bcast.s_addr = htonl((A << 24) | (B << 16) | (C << 8) | D); break; usage_error: default: fprintf(stderr, "%s:\n\tUsage:\n\t\t-l\t\t\t\t\tlist interfaces\n\t\t-a <interface> <ip> <bcast> <netmask>\tAdd this VIP\n\t\t-d <IP>\t\t\t\t\tDelete this VIP\n\t\t-s interface VIP destinationIP\n", argv[0]); exit(-1); } if_initialize(); if(state&ARPLIST) { arp_entry *ad, *ac; fprintf(stderr, "Sampling and printing local arp-cache\n"); sample_arp_cache(); sample_arp_cache(); ac = ad = fetch_shared_arp_cache(); while(ad && ad->ip) { struct in_addr iad; iad.s_addr = ad->ip; fprintf(stderr, "\t%s\n", inet_ntoa(iad)); ad++; } free(ac); } if(state&ADD) { ic = if_up(&req); if(ic) { perror("ioctl"); fprintf(stderr, "%s\n", if_error()); } else { fprintf(stderr, "if_up: %s\t%s", req.ifname, inet_ntoa(req.ipaddr)); fprintf(stderr, "\t%s", inet_ntoa(req.bcast)); fprintf(stderr, "\t%s\n", inet_ntoa(req.netmask)); } } if(state&DELETE) { ic = if_down(&req); if(ic) fprintf(stderr, "%s\n", if_error()); else { fprintf(stderr, "if_down: %s\t%s", req.ifname, inet_ntoa(req.ipaddr)); fprintf(stderr, "\t%s", inet_ntoa(req.bcast)); fprintf(stderr, "\t%s\n", inet_ntoa(req.netmask)); } } if(state&SPOOF) { ic = if_send_spoof_request(req.ifname, req.ipaddr.s_addr, req.bcast.s_addr, NULL, 5, 0); if(ic) fprintf(stderr, "%s\n", if_error()); else { fprintf(stderr, "if_spoofed: %s\t%s\n",req.ifname, inet_ntoa(req.ipaddr)); } } if(state) { ic = if_list_ips(myips, 300); fprintf(stderr, "Found %d IPs:\n", ic); for(i=0; i<ic; i++) { fprintf(stderr, "%s\t[%02x:%02x:%02x:%02x:%02x:%02x]", myips[i].ifname, myips[i].mac[0], myips[i].mac[1], myips[i].mac[2], myips[i].mac[3], myips[i].mac[4], myips[i].mac[5]); fprintf(stderr, "\t%s", inet_ntoa(myips[i].ipaddr)); fprintf(stderr, "\t%s", inet_ntoa(myips[i].bcast)); fprintf(stderr, "\t%s\n", inet_ntoa(myips[i].netmask)); } } return 0; }
int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) { int len; struct ifinfomsg *ifi; struct rtattr *tb[IFLA_MAX + 1]; struct rtattr *linkinfo[IFLA_MAX + 1]; struct interface *ifp; char *name = NULL; char *kind = NULL; char *desc = NULL; char *slave_kind = NULL; struct zebra_ns *zns; vrf_id_t vrf_id = VRF_DEFAULT; zebra_iftype_t zif_type = ZEBRA_IF_OTHER; zebra_slave_iftype_t zif_slave_type = ZEBRA_IF_SLAVE_NONE; ifindex_t bridge_ifindex = IFINDEX_INTERNAL; ifindex_t link_ifindex = IFINDEX_INTERNAL; zns = zebra_ns_lookup(ns_id); ifi = NLMSG_DATA(h); /* assume if not default zns, then new VRF */ if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)) { /* If this is not link add/delete message so print warning. */ zlog_warn("netlink_link_change: wrong kernel message %d", h->nlmsg_type); return 0; } if (!(ifi->ifi_family == AF_UNSPEC || ifi->ifi_family == AF_BRIDGE || ifi->ifi_family == AF_INET6)) { zlog_warn( "Invalid address family: %u received from kernel link change: %u", ifi->ifi_family, h->nlmsg_type); return 0; } len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg)); if (len < 0) { zlog_err("%s: Message received from netlink is of a broken size %d %zu", __PRETTY_FUNCTION__, h->nlmsg_len, (size_t)NLMSG_LENGTH(sizeof(struct ifinfomsg))); return -1; } /* We are interested in some AF_BRIDGE notifications. */ if (ifi->ifi_family == AF_BRIDGE) return netlink_bridge_interface(h, len, ns_id, startup); /* Looking up interface name. */ memset(tb, 0, sizeof tb); memset(linkinfo, 0, sizeof linkinfo); netlink_parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); /* check for wireless messages to ignore */ if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0)) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("%s: ignoring IFLA_WIRELESS message", __func__); return 0; } if (tb[IFLA_IFNAME] == NULL) return -1; name = (char *)RTA_DATA(tb[IFLA_IFNAME]); if (tb[IFLA_LINKINFO]) { parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]); if (linkinfo[IFLA_INFO_KIND]) kind = RTA_DATA(linkinfo[IFLA_INFO_KIND]); if (linkinfo[IFLA_INFO_SLAVE_KIND]) slave_kind = RTA_DATA(linkinfo[IFLA_INFO_SLAVE_KIND]); netlink_determine_zebra_iftype(kind, &zif_type); } /* If linking to another interface, note it. */ if (tb[IFLA_LINK]) link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]); if (tb[IFLA_IFALIAS]) { desc = (char *)RTA_DATA(tb[IFLA_IFALIAS]); } /* If VRF, create or update the VRF structure itself. */ if (zif_type == ZEBRA_IF_VRF && !vrf_is_backend_netns()) { netlink_vrf_change(h, tb[IFLA_LINKINFO], name); vrf_id = (vrf_id_t)ifi->ifi_index; } /* See if interface is present. */ ifp = if_lookup_by_name_per_ns(zns, name); if (ifp) { if (ifp->desc) XFREE(MTYPE_TMP, ifp->desc); if (desc) ifp->desc = XSTRDUP(MTYPE_TMP, desc); } if (h->nlmsg_type == RTM_NEWLINK) { if (tb[IFLA_MASTER]) { if (slave_kind && (strcmp(slave_kind, "vrf") == 0) && !vrf_is_backend_netns()) { zif_slave_type = ZEBRA_IF_SLAVE_VRF; vrf_id = *(uint32_t *)RTA_DATA(tb[IFLA_MASTER]); } else if (slave_kind && (strcmp(slave_kind, "bridge") == 0)) { zif_slave_type = ZEBRA_IF_SLAVE_BRIDGE; bridge_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_MASTER]); } else zif_slave_type = ZEBRA_IF_SLAVE_OTHER; } if (vrf_is_backend_netns()) vrf_id = (vrf_id_t)ns_id; if (ifp == NULL || !CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { /* Add interface notification from kernel */ if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( "RTM_NEWLINK ADD for %s(%u) vrf_id %u type %d " "sl_type %d master %u flags 0x%x", name, ifi->ifi_index, vrf_id, zif_type, zif_slave_type, bridge_ifindex, ifi->ifi_flags); if (ifp == NULL) { /* unknown interface */ ifp = if_get_by_name(name, vrf_id, 0); } else { /* pre-configured interface, learnt now */ if (ifp->vrf_id != vrf_id) if_update_to_new_vrf(ifp, vrf_id); } /* Update interface information. */ set_ifindex(ifp, ifi->ifi_index, zns); ifp->flags = ifi->ifi_flags & 0x0000fffff; if (!tb[IFLA_MTU]) { zlog_warn( "RTM_NEWLINK for interface %s(%u) without MTU set", name, ifi->ifi_index); return 0; } ifp->mtu6 = ifp->mtu = *(int *)RTA_DATA(tb[IFLA_MTU]); ifp->metric = 0; ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN; /* Set interface type */ zebra_if_set_ziftype(ifp, zif_type, zif_slave_type); if (IS_ZEBRA_IF_VRF(ifp)) SET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK); /* Update link. */ zebra_if_update_link(ifp, link_ifindex); netlink_interface_update_hw_addr(tb, ifp); /* Inform clients, install any configured addresses. */ if_add_update(ifp); /* Extract and save L2 interface information, take * additional actions. */ netlink_interface_update_l2info( ifp, linkinfo[IFLA_INFO_DATA], 1); if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) zebra_l2if_update_bridge_slave(ifp, bridge_ifindex); if_netlink_check_ifp_instance_consistency(RTM_NEWLINK, ifp, ns_id); } else if (ifp->vrf_id != vrf_id) { /* VRF change for an interface. */ if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( "RTM_NEWLINK vrf-change for %s(%u) " "vrf_id %u -> %u flags 0x%x", name, ifp->ifindex, ifp->vrf_id, vrf_id, ifi->ifi_flags); if_handle_vrf_change(ifp, vrf_id); } else { int was_bridge_slave; /* Interface update. */ if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( "RTM_NEWLINK update for %s(%u) " "sl_type %d master %u flags 0x%x", name, ifp->ifindex, zif_slave_type, bridge_ifindex, ifi->ifi_flags); set_ifindex(ifp, ifi->ifi_index, zns); if (!tb[IFLA_MTU]) { zlog_warn( "RTM_NEWLINK for interface %s(%u) without MTU set", name, ifi->ifi_index); return 0; } ifp->mtu6 = ifp->mtu = *(int *)RTA_DATA(tb[IFLA_MTU]); ifp->metric = 0; /* Update interface type - NOTE: Only slave_type can * change. */ was_bridge_slave = IS_ZEBRA_IF_BRIDGE_SLAVE(ifp); zebra_if_set_ziftype(ifp, zif_type, zif_slave_type); netlink_interface_update_hw_addr(tb, ifp); if (if_is_no_ptm_operative(ifp)) { ifp->flags = ifi->ifi_flags & 0x0000fffff; if (!if_is_no_ptm_operative(ifp)) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( "Intf %s(%u) has gone DOWN", name, ifp->ifindex); if_down(ifp); } else if (if_is_operative(ifp)) { /* Must notify client daemons of new * interface status. */ if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( "Intf %s(%u) PTM up, notifying clients", name, ifp->ifindex); zebra_interface_up_update(ifp); } } else { ifp->flags = ifi->ifi_flags & 0x0000fffff; if (if_is_operative(ifp)) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( "Intf %s(%u) has come UP", name, ifp->ifindex); if_up(ifp); } } /* Extract and save L2 interface information, take * additional actions. */ netlink_interface_update_l2info( ifp, linkinfo[IFLA_INFO_DATA], 0); if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) || was_bridge_slave) zebra_l2if_update_bridge_slave(ifp, bridge_ifindex); if_netlink_check_ifp_instance_consistency(RTM_NEWLINK, ifp, ns_id); } } else { /* Delete interface notification from kernel */ if (ifp == NULL) { zlog_warn("RTM_DELLINK for unknown interface %s(%u)", name, ifi->ifi_index); return 0; } if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("RTM_DELLINK for %s(%u)", name, ifp->ifindex); UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK); /* Special handling for bridge or VxLAN interfaces. */ if (IS_ZEBRA_IF_BRIDGE(ifp)) zebra_l2_bridge_del(ifp); else if (IS_ZEBRA_IF_VXLAN(ifp)) zebra_l2_vxlanif_del(ifp); if (!IS_ZEBRA_IF_VRF(ifp)) if_delete_update(ifp); if_netlink_check_ifp_instance_consistency(RTM_DELLINK, ifp, ns_id); } return 0; }
/* * Execute an individual uptest. Call with locks applied */ static int uptest (servparm_t *serv, int j) { int ret=0, count_running_ping=0; pdnsd_a *s_addr= PDNSD_A2_TO_A(&DA_INDEX(serv->atup_a,j).a); DEBUG_PDNSDA_MSG("performing uptest (type=%s) for %s\n",const_name(serv->uptest),PDNSDA2STR(s_addr)); /* Unlock the mutex because some of the tests may take a while. */ ++server_data_users; if((serv->uptest==C_PING || serv->uptest==C_QUERY) && pthread_equal(pthread_self(),servstat_thrid)) { /* Inform other threads that a ping is in progress. */ count_running_ping=1; ++server_status_ping; } pthread_mutex_unlock(&servers_lock); switch (serv->uptest) { case C_NONE: /* Don't change */ ret=DA_INDEX(serv->atup_a,j).is_up; break; case C_PING: ret=ping(is_inaddr_any(&serv->ping_a) ? s_addr : &serv->ping_a, serv->ping_timeout,PINGREPEAT)!=-1; break; case C_IF: case C_DEV: case C_DIALD: ret=if_up(serv->interface); #if (TARGET==TARGET_LINUX) if (ret!=0) { if(serv->uptest==C_DEV) ret=dev_up(serv->interface,serv->device); else if (serv->uptest==C_DIALD) ret=dev_up("diald",serv->device); } #endif break; case C_EXEC: { pid_t pid; if ((pid=fork())==-1) { DEBUG_MSG("Could not fork to perform exec uptest: %s\n",strerror(errno)); break; } else if (pid==0) { /* child */ /* * If we ran as setuid or setgid, do not inherit this to the * command. This is just a last guard. Running pdnsd as setuid() * or setgid() is a no-no. */ if (setgid(getgid()) == -1 || setuid(getuid()) == -1) { log_error("Could not reset uid or gid: %s",strerror(errno)); _exit(1); } /* Try to setuid() to a different user as specified. Good when you don't want the test command to run as root */ if (!run_as(serv->uptest_usr)) { _exit(1); } { struct rlimit rl; int i; /* * Mark all open fd's FD_CLOEXEC for paranoia reasons. */ if (getrlimit(RLIMIT_NOFILE, &rl) == -1) { log_error("getrlimit() failed: %s",strerror(errno)); _exit(1); } for (i = 0; i < rl.rlim_max; i++) { if (fcntl(i, F_SETFD, FD_CLOEXEC) == -1 && errno != EBADF) { log_error("fcntl(F_SETFD) failed: %s",strerror(errno)); _exit(1); } } } execl("/bin/sh", "uptest_sh","-c",serv->uptest_cmd,(char *)NULL); _exit(1); /* failed execl */ } else { /* parent */ int status; pid_t wpid = waitpid(pid,&status,0); if (wpid==pid) { if(WIFEXITED(status)) { int exitstatus=WEXITSTATUS(status); DEBUG_MSG("uptest command \"%s\" exited with status %d\n", serv->uptest_cmd, exitstatus); ret=(exitstatus==0); } #if DEBUG>0 else if(WIFSIGNALED(status)) { DEBUG_MSG("uptest command \"%s\" was terminated by signal %d\n", serv->uptest_cmd, WTERMSIG(status)); } else { DEBUG_MSG("status of uptest command \"%s\" is of unkown type (0x%x)\n", serv->uptest_cmd, status); } #endif } #if DEBUG>0 else if (wpid==-1) { DEBUG_MSG("Error while waiting for uptest command \"%s\" to terminate: " "waitpid for pid %d failed: %s\n", serv->uptest_cmd, pid, strerror(errno)); } else { DEBUG_MSG("Error while waiting for uptest command \"%s\" to terminate: " "waitpid returned %d, expected pid %d\n", serv->uptest_cmd, wpid, pid); } #endif } } break; case C_QUERY: ret=query_uptest(s_addr, serv->port, serv->timeout>=global.timeout?serv->timeout:global.timeout, PINGREPEAT); } /* end of switch */ pthread_mutex_lock(&servers_lock); if(count_running_ping) --server_status_ping; PDNSD_ASSERT(server_data_users>0, "server_data_users non-positive before attempt to decrement it"); if (--server_data_users==0) pthread_cond_broadcast(&server_data_cond); DEBUG_PDNSDA_MSG("result of uptest for %s: %s\n", PDNSDA2STR(s_addr), ret?"OK":"failed"); return ret; }
/* Interface adding function called from interface_list. */ int ifm_read (struct if_msghdr *ifm) { struct interface *ifp; struct sockaddr_dl *sdl = NULL; sdl = (struct sockaddr_dl *)(ifm + 1); /* Use sdl index. */ ifp = if_lookup_by_index (ifm->ifm_index); if (ifp == NULL) { /* Check interface's address.*/ if (! (ifm->ifm_addrs & RTA_IFP)) { zlog_warn ("There must be RTA_IFP address for ifindex %d\n", ifm->ifm_index); return -1; } ifp = if_create (); strncpy (ifp->name, sdl->sdl_data, sdl->sdl_nlen); ifp->ifindex = ifm->ifm_index; ifp->flags = ifm->ifm_flags; #if defined(__bsdi__) if_kvm_get_mtu (ifp); #else if_get_mtu (ifp); #endif /* __bsdi__ */ if_get_metric (ifp); /* Fetch hardware address. */ if (sdl->sdl_family != AF_LINK) { zlog_warn ("sockaddr_dl->sdl_family is not AF_LINK"); return -1; } memcpy (&ifp->sdl, sdl, sizeof (struct sockaddr_dl)); if_add_update (ifp); } else { /* There is a case of promisc, allmulti flag modification. */ if (if_is_up (ifp)) { ifp->flags = ifm->ifm_flags; if (! if_is_up (ifp)) if_down (ifp); } else { ifp->flags = ifm->ifm_flags; if (if_is_up (ifp)) if_up (ifp); } } #ifdef HAVE_NET_RT_IFLIST ifp->stats = ifm->ifm_data; #endif /* HAVE_NET_RT_IFLIST */ if (IS_ZEBRA_DEBUG_KERNEL) zlog_info ("interface %s index %d", ifp->name, ifp->ifindex); return 0; }
/* * Interface ioctls. */ int ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p) { struct ifnet *ifp; struct ifreq *ifr; int error; switch (cmd) { case SIOCGIFCONF: case OSIOCGIFCONF: return (ifconf(cmd, data)); } ifr = (struct ifreq *)data; ifp = ifunit(ifr->ifr_name); if (ifp == 0) return (ENXIO); switch (cmd) { case SIOCGIFFLAGS: ifr->ifr_flags = ifp->if_flags; break; case SIOCGIFMETRIC: ifr->ifr_metric = ifp->if_metric; break; case SIOCGIFMTU: ifr->ifr_mtu = ifp->if_mtu; break; case SIOCGIFPHYS: ifr->ifr_phys = ifp->if_physical; break; case SIOCSIFFLAGS: error = suser(p->p_ucred, &p->p_acflag); if (error) return (error); if (ifp->if_flags & IFF_UP && (ifr->ifr_flags & IFF_UP) == 0) { int s = splimp(); if_down(ifp); splx(s); } if (ifr->ifr_flags & IFF_UP && (ifp->if_flags & IFF_UP) == 0) { int s = splimp(); if_up(ifp); splx(s); } ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | (ifr->ifr_flags &~ IFF_CANTCHANGE); if (ifp->if_ioctl) (void) (*ifp->if_ioctl)(ifp, cmd, data); microtime(&ifp->if_lastchange); break; case SIOCSIFMETRIC: error = suser(p->p_ucred, &p->p_acflag); if (error) return (error); ifp->if_metric = ifr->ifr_metric; microtime(&ifp->if_lastchange); break; case SIOCSIFPHYS: error = suser(p->p_ucred, &p->p_acflag); if (error) return error; if (!ifp->if_ioctl) return EOPNOTSUPP; error = (*ifp->if_ioctl)(ifp, cmd, data); if (error == 0) microtime(&ifp->if_lastchange); return(error); case SIOCSIFMTU: error = suser(p->p_ucred, &p->p_acflag); if (error) return (error); if (ifp->if_ioctl == NULL) return (EOPNOTSUPP); /* * 72 was chosen below because it is the size of a TCP/IP * header (40) + the minimum mss (32). */ if (ifr->ifr_mtu < 72 || ifr->ifr_mtu > 65535L) return (EINVAL); error = (*ifp->if_ioctl)(ifp, cmd, data); if (error == 0) microtime(&ifp->if_lastchange); return(error); case SIOCADDMULTI: case SIOCDELMULTI: error = suser(p->p_ucred, &p->p_acflag); if (error) return (error); if (ifp->if_ioctl == NULL) return (EOPNOTSUPP); error = (*ifp->if_ioctl)(ifp, cmd, data); if (error == 0 ) microtime(&ifp->if_lastchange); return(error); case SIOCSIFMEDIA: error = suser(p->p_ucred, &p->p_acflag); if (error) return (error); if (ifp->if_ioctl == NULL) return (EOPNOTSUPP); error = (*ifp->if_ioctl)(ifp, cmd, data); if (error == 0) microtime(&ifp->if_lastchange); return error; case SIOCGIFMEDIA: if (ifp->if_ioctl == NULL) return (EOPNOTSUPP); return ((*ifp->if_ioctl)(ifp, cmd, data)); default: if (so->so_proto == 0) return (EOPNOTSUPP); #ifndef COMPAT_43 return ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd, data, ifp)); #else { int ocmd = cmd; switch (cmd) { case SIOCSIFDSTADDR: case SIOCSIFADDR: case SIOCSIFBRDADDR: case SIOCSIFNETMASK: #if BYTE_ORDER != BIG_ENDIAN if (ifr->ifr_addr.sa_family == 0 && ifr->ifr_addr.sa_len < 16) { ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len; ifr->ifr_addr.sa_len = 16; } #else if (ifr->ifr_addr.sa_len == 0) ifr->ifr_addr.sa_len = 16; #endif break; case OSIOCGIFADDR: cmd = SIOCGIFADDR; break; case OSIOCGIFDSTADDR: cmd = SIOCGIFDSTADDR; break; case OSIOCGIFBRDADDR: cmd = SIOCGIFBRDADDR; break; case OSIOCGIFNETMASK: cmd = SIOCGIFNETMASK; } error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd, data, ifp)); switch (ocmd) { case OSIOCGIFADDR: case OSIOCGIFDSTADDR: case OSIOCGIFBRDADDR: case OSIOCGIFNETMASK: *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family; } return (error); } #endif /* * RTEMS additions for setting/getting `tap' function */ case SIOCSIFTAP: ifp->if_tap = ifr->ifr_tap; return 0; case SIOCGIFTAP: ifr->ifr_tap = ifp->if_tap; return 0; } return (0); }