static int ipnetns_have_nsid(void) { struct { struct nlmsghdr n; struct rtgenmsg g; char buf[1024]; } req; int fd; if (have_rtnl_getnsid < 0) { memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_GETNSID; req.g.rtgen_family = AF_UNSPEC; fd = open("/proc/self/ns/net", O_RDONLY); if (fd < 0) { perror("open(\"/proc/self/ns/net\")"); exit(1); } addattr32(&req.n, 1024, NETNSA_FD, fd); if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) { perror("request send failed"); exit(1); } rtnl_listen(&rth, ipnetns_accept_msg, NULL); close(fd); } return have_rtnl_getnsid; }
static int do_show(int argc, char **argv) { struct { struct nlmsghdr n; struct netconfmsg ncm; char buf[1024]; } req; ipnetconf_reset_filter(0); filter.family = preferred_family; if (filter.family == AF_UNSPEC) filter.family = AF_INET; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); filter.ifindex = ll_name_to_index(*argv); if (filter.ifindex <= 0) { fprintf(stderr, "Device \"%s\" does not exist.\n", *argv); return -1; } } argv++; argc--; } ll_init_map(&rth); if (filter.ifindex) { memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct netconfmsg)); req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; req.n.nlmsg_type = RTM_GETNETCONF; req.ncm.ncm_family = filter.family; if (filter.ifindex) addattr_l(&req.n, sizeof(req), NETCONFA_IFINDEX, &filter.ifindex, sizeof(filter.ifindex)); if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) { perror("Can not send request"); exit(1); } rtnl_listen(&rth, print_netconf, stdout); } else { dump: if (rtnl_wilddump_request(&rth, filter.family, RTM_GETNETCONF) < 0) { perror("Cannot send dump request"); exit(1); } if (rtnl_dump_filter(&rth, print_netconf2, stdout) < 0) { fprintf(stderr, "Dump terminated\n"); exit(1); } if (preferred_family == AF_UNSPEC) { preferred_family = AF_INET6; filter.family = AF_INET6; goto dump; } } return 0; }
void neigh_flush_table(char *iface) { struct rtnl_handle rth; char flushb[4096-512]; DEBUG_MSG("neigh_flush_table %s", iface); memset(&filter, 0, sizeof(filter)); filter.state = ~0; filter.family = AF_INET; /* flush all but permanent and noarp */ filter.state = ~(NUD_PERMANENT|NUD_NOARP); /* open the netlink socket */ if (rtnl_open(&rth, 0) < 0) ERROR_MSG("rtnl_open()"); ll_init_map(&rth); /* fill the device data */ if ((filter.index = ll_name_to_index(iface)) == 0) ERROR_MSG("ll_name_to_index(%s)", iface); filter.flushb = flushb; filter.flushp = 0; filter.flushe = sizeof(flushb); filter.rth = &rth; filter.state &= ~NUD_FAILED; for (;;) { if (rtnl_wilddump_request(&rth, filter.family, RTM_GETNEIGH) < 0) ERROR_MSG("rtnl_wilddump_request()"); filter.flushed = 0; /* * count how many neigh are to be flushed * and prepare the data */ if (rtnl_dump_filter(&rth, count_neigh, stdout, NULL, NULL) < 0) ERROR_MSG("rtnl_dump_filter()"); if (filter.flushed == 0) return; if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) ERROR_MSG("rtnl_send()"); filter.flushp = 0; DEBUG_MSG("*** deleting %d entries ***", filter.flushed); } }
static int iplink_have_newlink(void) { struct iplink_req req; struct softgred_config *cfg = softgred_config_ref(); if (have_rtnl_newlink < 0) { memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; req.n.nlmsg_type = RTM_NEWLINK; req.i.ifi_family = AF_UNSPEC; if (rtnl_send(&cfg->rth, &req.n, req.n.nlmsg_len) < 0) { perror("request send failed"); exit(1); } rtnl_listen(&cfg->rth, accept_msg, NULL); } return have_rtnl_newlink; }
/* * All the code below this point is ripped from iproute2/iproute.c * written by Alexey Kuznetsov, <*****@*****.**>. * * Modified lightly */ static int flush_update(void) { if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) { error("Failed to send flush request: %s", strerror(errno)); return -1; } filter.flushp = 0; return 0; }
static int flush_update(void) { if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) { perror("Failed to send flush request\n"); return -1; } filter.flushp = 0; return 0; }
static int flush_update(void) { if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) { bb_perror_msg("failed to send flush request"); return -1; } filter.flushp = 0; return 0; }
static int flush_update(void) { if (rtnl_send(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) { bb_perror_msg("can't send flush request"); return -1; } G_filter.flushp = 0; return 0; }
int FAST_FUNC xrtnl_wilddump_request(struct rtnl_handle *rth, int family, int type) { struct { struct nlmsghdr nlh; struct rtgenmsg g; } req; req.nlh.nlmsg_len = sizeof(req); req.nlh.nlmsg_type = type; req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; req.nlh.nlmsg_pid = 0; req.nlh.nlmsg_seq = rth->dump = ++rth->seq; req.g.rtgen_family = family; return rtnl_send(rth, (void*)&req, sizeof(req)); }
static int iplink_have_newlink(void) { struct { struct nlmsghdr n; struct ifinfomsg i; char buf[1024]; } req = { .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK, .n.nlmsg_type = RTM_NEWLINK, .i.ifi_family = AF_UNSPEC, }; if (have_rtnl_newlink < 0) { if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) { perror("request send failed"); exit(1); } rtnl_listen(&rth, accept_msg, NULL); } return have_rtnl_newlink; } #else /* IPLINK_IOCTL_COMPAT */ static int iplink_have_newlink(void) { return 1; } #endif /* ! IPLINK_IOCTL_COMPAT */ static int nl_get_ll_addr_len(unsigned int dev_index) { int len; struct iplink_req req = { .n = { .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), .nlmsg_type = RTM_GETLINK, .nlmsg_flags = NLM_F_REQUEST }, .i = { .ifi_family = preferred_family, .ifi_index = dev_index, } };
static int iplink_have_newlink(void) { struct { struct nlmsghdr n; struct ifinfomsg i; char buf[1024]; } req; if (have_rtnl_newlink < 0) { memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; req.n.nlmsg_type = RTM_NEWLINK; req.i.ifi_family = AF_UNSPEC; rtnl_send(&rth, &req.n, req.n.nlmsg_len); rtnl_listen(&rth, accept_msg, NULL); } return have_rtnl_newlink; }
static int get_tunnel(struct l2tp_data *p) { GENL_REQUEST(req, 1024, genl_family, 0, L2TP_GENL_VERSION, L2TP_CMD_TUNNEL_GET, NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST); req.n.nlmsg_seq = genl_rth.dump = ++genl_rth.seq; if (p->config.tunnel_id) addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->config.tunnel_id); if (rtnl_send(&genl_rth, &req, req.n.nlmsg_len) < 0) return -2; if (rtnl_dump_filter(&genl_rth, tunnel_nlmsg, p) < 0) { fprintf(stderr, "Dump terminated\n"); exit(1); } return 0; }
int mpls_list(int cmd,int argc, char **argv) { struct genlmsghdr *ghdr; struct rtnl_handle rth; struct { struct nlmsghdr n; char buf[4096]; } req; if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) { fprintf (stderr, "Error opening nl socket\n"); //exit(-1); return -1; } memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); req.n.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; req.n.nlmsg_type = PF_MPLS; req.n.nlmsg_seq = rth.dump = ++rth.seq; ghdr = NLMSG_DATA(&req.n); ghdr->cmd = cmd; if (rtnl_send(&rth, (const char *)&req.n, req.n.nlmsg_len) < 0) { perror("Cannot send dump request"); //exit(1); return 1; } if (rtnl_dump_filter(&rth, print_mpls, stdout, NULL, NULL) < 0) { fprintf(stderr, "Dump terminated\n"); //exit(1); return 1; } rtnl_close(&rth); return 0; }
static int do_list(int argc, char **argv) { ILA_REQUEST(req, 1024, ILA_CMD_GET, NLM_F_REQUEST | NLM_F_DUMP); if (argc > 0) { fprintf(stderr, "\"ip ila show\" does not take " "any arguments.\n"); return -1; } if (rtnl_send(&genl_rth, (void *)&req, req.n.nlmsg_len) < 0) { perror("Cannot send dump request"); exit(1); } if (rtnl_dump_filter(&genl_rth, print_ila_mapping, stdout) < 0) { fprintf(stderr, "Dump terminated\n"); return 1; } return 0; }
int count_neigh(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { struct ndmsg *r = NLMSG_DATA(n); if (filter.flushb && n->nlmsg_type != RTM_NEWNEIGH) return 0; if (filter.family && filter.family != r->ndm_family) return 0; if (filter.index && filter.index != r->ndm_ifindex) return 0; if (!(filter.state & r->ndm_state) && (r->ndm_state || !(filter.state & 0x100)) && (r->ndm_family != AF_DECnet)) return 0; if (filter.flushb) { struct nlmsghdr *fn; if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) { if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) return -1; filter.flushp = 0; } fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp)); memcpy(fn, n, n->nlmsg_len); fn->nlmsg_type = RTM_DELNEIGH; fn->nlmsg_flags = NLM_F_REQUEST; fn->nlmsg_seq = ++filter.rth->seq; filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb; filter.flushed++; } return 0; }
int respond_to_kernel(int ifindex, __u32 addr, char *lla, int llalen) { struct { struct nlmsghdr n; struct ndmsg ndm; char buf[256]; } req; memset(&req.n, 0, sizeof(req.n)); memset(&req.ndm, 0, sizeof(req.ndm)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_NEWNEIGH; req.ndm.ndm_family = AF_INET; req.ndm.ndm_state = NUD_STALE; req.ndm.ndm_ifindex = ifindex; req.ndm.ndm_type = RTN_UNICAST; addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4); addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen); return rtnl_send(&rth, (char*)&req, req.n.nlmsg_len) <= 0; }
static int do_dump(int ifindex) { MACSEC_GENL_REQ(req, MACSEC_BUFLEN, MACSEC_CMD_GET_TXSC, NLM_F_REQUEST | NLM_F_DUMP); memset(&filter, 0, sizeof(filter)); filter.ifindex = ifindex; req.n.nlmsg_seq = genl_rth.dump = ++genl_rth.seq; if (rtnl_send(&genl_rth, &req, req.n.nlmsg_len) < 0) { perror("Failed to send dump request"); exit(1); } new_json_obj(json); if (rtnl_dump_filter(&genl_rth, process, stdout) < 0) { delete_json_obj(); fprintf(stderr, "Dump terminated\n"); exit(1); } delete_json_obj(); return 0; }
static int send_probe(int ifindex, __u32 addr) { struct ifreq ifr = { .ifr_ifindex = ifindex }; struct sockaddr_in dst = { .sin_family = AF_INET, .sin_port = htons(1025), .sin_addr.s_addr = addr, }; socklen_t len; unsigned char buf[256]; struct arphdr *ah = (struct arphdr *)buf; unsigned char *p = (unsigned char *)(ah+1); struct sockaddr_ll sll = { .sll_family = AF_PACKET, .sll_ifindex = ifindex, .sll_protocol = htons(ETH_P_ARP), }; if (ioctl(udp_sock, SIOCGIFNAME, &ifr)) return -1; if (ioctl(udp_sock, SIOCGIFHWADDR, &ifr)) return -1; if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) return -1; if (setsockopt(udp_sock, SOL_SOCKET, SO_BINDTODEVICE, ifr.ifr_name, strlen(ifr.ifr_name)+1) < 0) return -1; if (connect(udp_sock, (struct sockaddr *)&dst, sizeof(dst)) < 0) return -1; len = sizeof(dst); if (getsockname(udp_sock, (struct sockaddr *)&dst, &len) < 0) return -1; ah->ar_hrd = htons(ifr.ifr_hwaddr.sa_family); ah->ar_pro = htons(ETH_P_IP); ah->ar_hln = 6; ah->ar_pln = 4; ah->ar_op = htons(ARPOP_REQUEST); memcpy(p, ifr.ifr_hwaddr.sa_data, ah->ar_hln); p += ah->ar_hln; memcpy(p, &dst.sin_addr, 4); p += 4; memset(sll.sll_addr, 0xFF, sizeof(sll.sll_addr)); memcpy(p, &sll.sll_addr, ah->ar_hln); p += ah->ar_hln; memcpy(p, &addr, 4); p += 4; if (sendto(pset[0].fd, buf, p-buf, 0, (struct sockaddr *)&sll, sizeof(sll)) < 0) return -1; stats.probes_sent++; return 0; } /* Be very tough on sending probes: 1 per second with burst of 3. */ static int queue_active_probe(int ifindex, __u32 addr) { static struct timeval prev; static int buckets; struct timeval now; gettimeofday(&now, NULL); if (prev.tv_sec) { int diff = (now.tv_sec-prev.tv_sec)*1000+(now.tv_usec-prev.tv_usec)/1000; buckets += diff; } else { buckets = broadcast_burst; } if (buckets > broadcast_burst) buckets = broadcast_burst; if (buckets >= broadcast_rate && !send_probe(ifindex, addr)) { buckets -= broadcast_rate; prev = now; return 0; } stats.probes_suppressed++; return -1; } static int respond_to_kernel(int ifindex, __u32 addr, char *lla, int llalen) { struct { struct nlmsghdr n; struct ndmsg ndm; char buf[256]; } req = { .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)), .n.nlmsg_flags = NLM_F_REQUEST, .n.nlmsg_type = RTM_NEWNEIGH, .ndm.ndm_family = AF_INET, .ndm.ndm_state = NUD_STALE, .ndm.ndm_ifindex = ifindex, .ndm.ndm_type = RTN_UNICAST, }; addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4); addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen); return rtnl_send(&rth, &req, req.n.nlmsg_len) <= 0; } static void prepare_neg_entry(__u8 *ndata, __u32 stamp) { ndata[0] = 0xFF; ndata[1] = 0; ndata[2] = stamp>>24; ndata[3] = stamp>>16; ndata[4] = stamp>>8; ndata[5] = stamp; } static int do_one_request(struct nlmsghdr *n) { struct ndmsg *ndm = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[NDA_MAX+1]; struct dbkey key; DBT dbkey, dbdat; int do_acct = 0; if (n->nlmsg_type == NLMSG_DONE) { dbase->sync(dbase, 0); /* Now we have at least mirror of kernel db, so that * may start real resolution. */ do_sysctl_adjustments(); return 0; } if (n->nlmsg_type != RTM_GETNEIGH && n->nlmsg_type != RTM_NEWNEIGH) return 0; len -= NLMSG_LENGTH(sizeof(*ndm)); if (len < 0) return -1; if (ndm->ndm_family != AF_INET || (ifnum && !handle_if(ndm->ndm_ifindex)) || ndm->ndm_flags || ndm->ndm_type != RTN_UNICAST || !(ndm->ndm_state&~NUD_NOARP)) return 0; parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len); if (!tb[NDA_DST]) return 0; key.iface = ndm->ndm_ifindex; memcpy(&key.addr, RTA_DATA(tb[NDA_DST]), 4); dbkey.data = &key; dbkey.size = sizeof(key); if (dbase->get(dbase, &dbkey, &dbdat, 0) != 0) { dbdat.data = 0; dbdat.size = 0; } if (n->nlmsg_type == RTM_GETNEIGH) { if (!(n->nlmsg_flags&NLM_F_REQUEST)) return 0; if (!(ndm->ndm_state&(NUD_PROBE|NUD_INCOMPLETE))) { stats.app_bad++; return 0; } if (ndm->ndm_state&NUD_PROBE) { /* If we get this, kernel still has some valid * address, but unicast probing failed and host * is either dead or changed its mac address. * Kernel is going to initiate broadcast resolution. * OK, we invalidate our information as well. */ if (dbdat.data && !IS_NEG(dbdat.data)) stats.app_neg++; dbase->del(dbase, &dbkey, 0); } else { /* If we get this kernel does not have any information. * If we have something tell this to kernel. */ stats.app_recv++; if (dbdat.data && !IS_NEG(dbdat.data)) { stats.app_success++; respond_to_kernel(key.iface, key.addr, dbdat.data, dbdat.size); return 0; } /* Sheeit! We have nothing to tell. */ /* If we have recent negative entry, be silent. */ if (dbdat.data && NEG_VALID(dbdat.data)) { if (NEG_CNT(dbdat.data) >= active_probing) { stats.app_suppressed++; return 0; } do_acct = 1; } } if (active_probing && queue_active_probe(ndm->ndm_ifindex, key.addr) == 0 && do_acct) { NEG_CNT(dbdat.data)++; dbase->put(dbase, &dbkey, &dbdat, 0); } } else if (n->nlmsg_type == RTM_NEWNEIGH) { if (n->nlmsg_flags&NLM_F_REQUEST) return 0; if (ndm->ndm_state&NUD_FAILED) { /* Kernel was not able to resolve. Host is dead. * Create negative entry if it is not present * or renew it if it is too old. */ if (!dbdat.data || !IS_NEG(dbdat.data) || !NEG_VALID(dbdat.data)) { __u8 ndata[6]; stats.kern_neg++; prepare_neg_entry(ndata, time(NULL)); dbdat.data = ndata; dbdat.size = sizeof(ndata); dbase->put(dbase, &dbkey, &dbdat, 0); } } else if (tb[NDA_LLADDR]) { if (dbdat.data && !IS_NEG(dbdat.data)) { if (memcmp(RTA_DATA(tb[NDA_LLADDR]), dbdat.data, dbdat.size) == 0) return 0; stats.kern_change++; } else { stats.kern_new++; } dbdat.data = RTA_DATA(tb[NDA_LLADDR]); dbdat.size = RTA_PAYLOAD(tb[NDA_LLADDR]); dbase->put(dbase, &dbkey, &dbdat, 0); } } return 0; } static void load_initial_table(void) { if (rtnl_wilddump_request(&rth, AF_INET, RTM_GETNEIGH) < 0) { perror("dump request failed"); exit(1); } } static void get_kern_msg(void) { int status; struct nlmsghdr *h; struct sockaddr_nl nladdr = {}; struct iovec iov; char buf[8192]; struct msghdr msg = { (void *)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 }; iov.iov_base = buf; iov.iov_len = sizeof(buf); status = recvmsg(rth.fd, &msg, MSG_DONTWAIT); if (status <= 0) return; if (msg.msg_namelen != sizeof(nladdr)) return; if (nladdr.nl_pid) return; for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) { int len = h->nlmsg_len; int l = len - sizeof(*h); if (l < 0 || len > status) return; if (do_one_request(h) < 0) return; status -= NLMSG_ALIGN(len); h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len)); } }
static int xfrm_policy_list_or_deleteall(int argc, char **argv, int deleteall) { char *selp = NULL; struct rtnl_handle rth; if (argc > 0) filter.use = 1; filter.xpinfo.sel.family = preferred_family; while (argc > 0) { if (strcmp(*argv, "dir") == 0) { NEXT_ARG(); xfrm_policy_dir_parse(&filter.xpinfo.dir, &argc, &argv); filter.dir_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "index") == 0) { NEXT_ARG(); if (get_u32(&filter.xpinfo.index, *argv, 0)) invarg("\"INDEX\" is invalid", *argv); filter.index_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "ptype") == 0) { NEXT_ARG(); xfrm_policy_ptype_parse(&filter.ptype, &argc, &argv); filter.ptype_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "action") == 0) { NEXT_ARG(); if (strcmp(*argv, "allow") == 0) filter.xpinfo.action = XFRM_POLICY_ALLOW; else if (strcmp(*argv, "block") == 0) filter.xpinfo.action = XFRM_POLICY_BLOCK; else invarg("\"ACTION\" is invalid\n", *argv); filter.action_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "priority") == 0) { NEXT_ARG(); if (get_u32(&filter.xpinfo.priority, *argv, 0)) invarg("\"PRIORITY\" is invalid", *argv); filter.priority_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "flag") == 0) { NEXT_ARG(); xfrm_policy_flag_parse(&filter.xpinfo.flags, &argc, &argv); filter.policy_flags_mask = XFRM_FILTER_MASK_FULL; } else { if (selp) invarg("unknown", *argv); selp = *argv; xfrm_selector_parse(&filter.xpinfo.sel, &argc, &argv); if (preferred_family == AF_UNSPEC) preferred_family = filter.xpinfo.sel.family; } argc--; argv++; } if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) exit(1); if (deleteall) { struct xfrm_buffer xb; char buf[NLMSG_DELETEALL_BUF_SIZE]; int i; xb.buf = buf; xb.size = sizeof(buf); xb.rth = &rth; for (i = 0; ; i++) { xb.offset = 0; xb.nlmsg_count = 0; if (show_stats > 1) fprintf(stderr, "Delete-all round = %d\n", i); if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETPOLICY) < 0) { perror("Cannot send dump request"); exit(1); } if (rtnl_dump_filter(&rth, xfrm_policy_keep, &xb, NULL, NULL) < 0) { fprintf(stderr, "Delete-all terminated\n"); exit(1); } if (xb.nlmsg_count == 0) { if (show_stats > 1) fprintf(stderr, "Delete-all completed\n"); break; } if (rtnl_send(&rth, xb.buf, xb.offset) < 0) { perror("Failed to send delete-all request\n"); exit(1); } if (show_stats > 1) fprintf(stderr, "Delete-all nlmsg count = %d\n", xb.nlmsg_count); xb.offset = 0; xb.nlmsg_count = 0; } } else { if (rtnl_wilddump_request(&rth, preferred_family, XFRM_MSG_GETPOLICY) < 0) { perror("Cannot send dump request"); exit(1); } if (rtnl_dump_filter(&rth, xfrm_policy_print, stdout, NULL, NULL) < 0) { fprintf(stderr, "Dump terminated\n"); exit(1); } } rtnl_close(&rth); exit(0); }
static int do_show(int argc, char **argv) { struct { struct nlmsghdr n; struct netconfmsg ncm; char buf[1024]; } req = { .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct netconfmsg)), .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK, .n.nlmsg_type = RTM_GETNETCONF, }; ipnetconf_reset_filter(0); filter.family = preferred_family; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); filter.ifindex = ll_name_to_index(*argv); if (filter.ifindex <= 0) { fprintf(stderr, "Device \"%s\" does not exist.\n", *argv); return -1; } } argv++; argc--; } ll_init_map(&rth); if (filter.ifindex && filter.family != AF_UNSPEC) { req.ncm.ncm_family = filter.family; addattr_l(&req.n, sizeof(req), NETCONFA_IFINDEX, &filter.ifindex, sizeof(filter.ifindex)); if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) { perror("Can not send request"); exit(1); } rtnl_listen(&rth, print_netconf, stdout); } else { rth.flags = RTNL_HANDLE_F_SUPPRESS_NLERR; dump: if (rtnl_wilddump_request(&rth, filter.family, RTM_GETNETCONF) < 0) { perror("Cannot send dump request"); exit(1); } if (rtnl_dump_filter(&rth, print_netconf2, stdout) < 0) { /* kernel does not support netconf dump on AF_UNSPEC; * fall back to requesting by family */ if (errno == EOPNOTSUPP && filter.family == AF_UNSPEC) { filter.family = AF_INET; goto dump; } perror("RTNETLINK answers"); fprintf(stderr, "Dump terminated\n"); exit(1); } if (preferred_family == AF_UNSPEC && filter.family == AF_INET) { preferred_family = AF_INET6; filter.family = AF_INET6; goto dump; } } return 0; } int do_ipnetconf(int argc, char **argv) { if (argc > 0) { if (matches(*argv, "show") == 0 || matches(*argv, "lst") == 0 || matches(*argv, "list") == 0) return do_show(argc-1, argv+1); if (matches(*argv, "help") == 0) usage(); } else return do_show(0, NULL); fprintf(stderr, "Command \"%s\" is unknown, try \"ip netconf help\".\n", *argv); exit(-1); }
static int xfrm_policy_list_or_deleteall(int argc, char **argv, int deleteall) { char *selp = NULL; struct rtnl_handle rth; if (argc > 0) filter.use = 1; filter.xpinfo.sel.family = preferred_family; while (argc > 0) { if (strcmp(*argv, "dir") == 0) { NEXT_ARG(); xfrm_policy_dir_parse(&filter.xpinfo.dir, &argc, &argv); filter.dir_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "index") == 0) { NEXT_ARG(); if (get_u32(&filter.xpinfo.index, *argv, 0)) invarg("INDEX value is invalid", *argv); filter.index_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "ptype") == 0) { NEXT_ARG(); xfrm_policy_ptype_parse(&filter.ptype, &argc, &argv); filter.ptype_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "action") == 0) { NEXT_ARG(); if (strcmp(*argv, "allow") == 0) filter.xpinfo.action = XFRM_POLICY_ALLOW; else if (strcmp(*argv, "block") == 0) filter.xpinfo.action = XFRM_POLICY_BLOCK; else invarg("ACTION value is invalid\n", *argv); filter.action_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "priority") == 0) { NEXT_ARG(); if (get_u32(&filter.xpinfo.priority, *argv, 0)) invarg("PRIORITY value is invalid", *argv); filter.priority_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "flag") == 0) { NEXT_ARG(); xfrm_policy_flag_parse(&filter.xpinfo.flags, &argc, &argv); filter.policy_flags_mask = XFRM_FILTER_MASK_FULL; } else { if (selp) invarg("unknown", *argv); selp = *argv; xfrm_selector_parse(&filter.xpinfo.sel, &argc, &argv); if (preferred_family == AF_UNSPEC) preferred_family = filter.xpinfo.sel.family; } argc--; argv++; } if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) exit(1); if (deleteall) { struct xfrm_buffer xb; char buf[NLMSG_DELETEALL_BUF_SIZE]; int i; xb.buf = buf; xb.size = sizeof(buf); xb.rth = &rth; for (i = 0; ; i++) { struct { struct nlmsghdr n; char buf[NLMSG_BUF_SIZE]; } req = { .n.nlmsg_len = NLMSG_HDRLEN, .n.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, .n.nlmsg_type = XFRM_MSG_GETPOLICY, .n.nlmsg_seq = rth.dump = ++rth.seq, }; xb.offset = 0; xb.nlmsg_count = 0; if (show_stats > 1) fprintf(stderr, "Delete-all round = %d\n", i); if (rtnl_send(&rth, (void *)&req, req.n.nlmsg_len) < 0) { perror("Cannot send dump request"); exit(1); } if (rtnl_dump_filter(&rth, xfrm_policy_keep, &xb) < 0) { fprintf(stderr, "Delete-all terminated\n"); exit(1); } if (xb.nlmsg_count == 0) { if (show_stats > 1) fprintf(stderr, "Delete-all completed\n"); break; } if (rtnl_send_check(&rth, xb.buf, xb.offset) < 0) { perror("Failed to send delete-all request"); exit(1); } if (show_stats > 1) fprintf(stderr, "Delete-all nlmsg count = %d\n", xb.nlmsg_count); xb.offset = 0; xb.nlmsg_count = 0; } } else { struct { struct nlmsghdr n; char buf[NLMSG_BUF_SIZE]; } req = { .n.nlmsg_len = NLMSG_HDRLEN, .n.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, .n.nlmsg_type = XFRM_MSG_GETPOLICY, .n.nlmsg_seq = rth.dump = ++rth.seq, }; if (rtnl_send(&rth, (void *)&req, req.n.nlmsg_len) < 0) { perror("Cannot send dump request"); exit(1); } if (rtnl_dump_filter(&rth, xfrm_policy_print, stdout) < 0) { fprintf(stderr, "Dump terminated\n"); exit(1); } } rtnl_close(&rth); exit(0); } static int print_spdinfo( struct nlmsghdr *n, void *arg) { FILE *fp = (FILE*)arg; __u32 *f = NLMSG_DATA(n); struct rtattr * tb[XFRMA_SPD_MAX+1]; struct rtattr * rta; int len = n->nlmsg_len; len -= NLMSG_LENGTH(sizeof(__u32)); if (len < 0) { fprintf(stderr, "SPDinfo: Wrong len %d\n", len); return -1; } rta = XFRMSAPD_RTA(f); parse_rtattr(tb, XFRMA_SPD_MAX, rta, len); fprintf(fp,"\t SPD"); if (tb[XFRMA_SPD_INFO]) { struct xfrmu_spdinfo *si; if (RTA_PAYLOAD(tb[XFRMA_SPD_INFO]) < sizeof(*si)) { fprintf(stderr, "SPDinfo: Wrong len %d\n", len); return -1; } si = RTA_DATA(tb[XFRMA_SPD_INFO]); fprintf(fp," IN %d", si->incnt); fprintf(fp," OUT %d", si->outcnt); fprintf(fp," FWD %d", si->fwdcnt); if (show_stats) { fprintf(fp," (Sock:"); fprintf(fp," IN %d", si->inscnt); fprintf(fp," OUT %d", si->outscnt); fprintf(fp," FWD %d", si->fwdscnt); fprintf(fp,")"); } fprintf(fp, "%s", _SL_); } if (show_stats > 1) { struct xfrmu_spdhinfo *sh; if (tb[XFRMA_SPD_HINFO]) { if (RTA_PAYLOAD(tb[XFRMA_SPD_HINFO]) < sizeof(*sh)) { fprintf(stderr, "SPDinfo: Wrong len %d\n", len); return -1; } sh = RTA_DATA(tb[XFRMA_SPD_HINFO]); fprintf(fp,"\t SPD buckets:"); fprintf(fp," count %d", sh->spdhcnt); fprintf(fp," Max %d", sh->spdhmcnt); fprintf(fp, "%s", _SL_); } if (tb[XFRMA_SPD_IPV4_HTHRESH]) { struct xfrmu_spdhthresh *th; if (RTA_PAYLOAD(tb[XFRMA_SPD_IPV4_HTHRESH]) < sizeof(*th)) { fprintf(stderr, "SPDinfo: Wrong len %d\n", len); return -1; } th = RTA_DATA(tb[XFRMA_SPD_IPV4_HTHRESH]); fprintf(fp,"\t SPD IPv4 thresholds:"); fprintf(fp," local %d", th->lbits); fprintf(fp," remote %d", th->rbits); fprintf(fp, "%s", _SL_); } if (tb[XFRMA_SPD_IPV6_HTHRESH]) { struct xfrmu_spdhthresh *th; if (RTA_PAYLOAD(tb[XFRMA_SPD_IPV6_HTHRESH]) < sizeof(*th)) { fprintf(stderr, "SPDinfo: Wrong len %d\n", len); return -1; } th = RTA_DATA(tb[XFRMA_SPD_IPV6_HTHRESH]); fprintf(fp,"\t SPD IPv6 thresholds:"); fprintf(fp," local %d", th->lbits); fprintf(fp," remote %d", th->rbits); fprintf(fp, "%s", _SL_); } } if (oneline) fprintf(fp, "\n"); return 0; }
static int tcpm_do_cmd(int cmd, int argc, char **argv) { TCPM_REQUEST(req, 1024, TCP_METRICS_CMD_GET, NLM_F_REQUEST); int atype = -1, stype = -1; int ack; memset(&f, 0, sizeof(f)); f.daddr.bitlen = -1; f.daddr.family = preferred_family; f.saddr.bitlen = -1; f.saddr.family = preferred_family; switch (preferred_family) { case AF_UNSPEC: case AF_INET: case AF_INET6: break; default: fprintf(stderr, "Unsupported protocol family: %d\n", preferred_family); return -1; } for (; argc > 0; argc--, argv++) { if (strcmp(*argv, "src") == 0 || strcmp(*argv, "source") == 0) { char *who = *argv; NEXT_ARG(); if (matches(*argv, "help") == 0) usage(); if (f.saddr.bitlen >= 0) duparg2(who, *argv); get_prefix(&f.saddr, *argv, preferred_family); if (f.saddr.bytelen && f.saddr.bytelen * 8 == f.saddr.bitlen) { if (f.saddr.family == AF_INET) stype = TCP_METRICS_ATTR_SADDR_IPV4; else if (f.saddr.family == AF_INET6) stype = TCP_METRICS_ATTR_SADDR_IPV6; } if (stype < 0) { fprintf(stderr, "Error: a specific IP address is expected rather than \"%s\"\n", *argv); return -1; } } else { char *who = "address"; if (strcmp(*argv, "addr") == 0 || strcmp(*argv, "address") == 0) { who = *argv; NEXT_ARG(); } if (matches(*argv, "help") == 0) usage(); if (f.daddr.bitlen >= 0) duparg2(who, *argv); get_prefix(&f.daddr, *argv, preferred_family); if (f.daddr.bytelen && f.daddr.bytelen * 8 == f.daddr.bitlen) { if (f.daddr.family == AF_INET) atype = TCP_METRICS_ATTR_ADDR_IPV4; else if (f.daddr.family == AF_INET6) atype = TCP_METRICS_ATTR_ADDR_IPV6; } if ((CMD_DEL & cmd) && atype < 0) { fprintf(stderr, "Error: a specific IP address is expected rather than \"%s\"\n", *argv); return -1; } } argc--; argv++; } if (cmd == CMD_DEL && atype < 0) missarg("address"); /* flush for exact address ? Single del */ if (cmd == CMD_FLUSH && atype >= 0) cmd = CMD_DEL; /* flush for all addresses ? Single del without address */ if (cmd == CMD_FLUSH && f.daddr.bitlen <= 0 && f.saddr.bitlen <= 0 && preferred_family == AF_UNSPEC) { cmd = CMD_DEL; req.g.cmd = TCP_METRICS_CMD_DEL; ack = 1; } else if (cmd == CMD_DEL) { req.g.cmd = TCP_METRICS_CMD_DEL; ack = 1; } else { /* CMD_FLUSH, CMD_LIST */ ack = 0; } if (genl_init_handle(&grth, TCP_METRICS_GENL_NAME, &genl_family)) exit(1); req.n.nlmsg_type = genl_family; if (!(cmd & CMD_FLUSH) && (atype >= 0 || (cmd & CMD_DEL))) { if (ack) req.n.nlmsg_flags |= NLM_F_ACK; if (atype >= 0) addattr_l(&req.n, sizeof(req), atype, &f.daddr.data, f.daddr.bytelen); if (stype >= 0) addattr_l(&req.n, sizeof(req), stype, &f.saddr.data, f.saddr.bytelen); } else { req.n.nlmsg_flags |= NLM_F_DUMP; } f.cmd = cmd; if (cmd & CMD_FLUSH) { int round = 0; char flushb[4096-512]; f.flushb = flushb; f.flushp = 0; f.flushe = sizeof(flushb); for (;;) { req.n.nlmsg_seq = grth.dump = ++grth.seq; if (rtnl_send(&grth, &req, req.n.nlmsg_len) < 0) { perror("Failed to send flush request"); exit(1); } f.flushed = 0; if (rtnl_dump_filter(&grth, process_msg, stdout) < 0) { fprintf(stderr, "Flush terminated\n"); exit(1); } if (f.flushed == 0) { if (round == 0) { fprintf(stderr, "Nothing to flush.\n"); } else if (show_stats) printf("*** Flush is complete after %d round%s ***\n", round, round > 1 ? "s" : ""); fflush(stdout); return 0; } round++; if (flush_update() < 0) exit(1); if (show_stats) { printf("\n*** Round %d, deleting %d entries ***\n", round, f.flushed); fflush(stdout); } } return 0; } if (ack) { if (rtnl_talk(&grth, &req.n, NULL, 0) < 0) return -2; } else if (atype >= 0) { if (rtnl_talk(&grth, &req.n, &req.n, sizeof(req)) < 0) return -2; if (process_msg(NULL, &req.n, stdout) < 0) { fprintf(stderr, "Dump terminated\n"); exit(1); } } else { req.n.nlmsg_seq = grth.dump = ++grth.seq; if (rtnl_send(&grth, &req, req.n.nlmsg_len) < 0) { perror("Failed to send dump request"); exit(1); } if (rtnl_dump_filter(&grth, process_msg, stdout) < 0) { fprintf(stderr, "Dump terminated\n"); exit(1); } } return 0; }
static int ctrl_list(int cmd, int argc, char **argv) { struct rtnl_handle rth; struct nlmsghdr *nlh; struct genlmsghdr *ghdr; int ret = -1; char d[GENL_NAMSIZ]; struct { struct nlmsghdr n; char buf[4096]; } req; memset(&req, 0, sizeof(req)); nlh = &req.n; nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; nlh->nlmsg_type = GENL_ID_CTRL; ghdr = NLMSG_DATA(&req.n); ghdr->cmd = CTRL_CMD_GETFAMILY; if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) { fprintf(stderr, "Cannot open generic netlink socket\n"); exit(1); } if (cmd == CTRL_CMD_GETFAMILY) { if (argc != 2) { fprintf(stderr, "Wrong number of params\n"); return -1; } if (matches(*argv, "name") == 0) { NEXT_ARG(); strncpy(d, *argv, sizeof (d) - 1); addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME, d, strlen(d) + 1); } else if (matches(*argv, "id") == 0) { __u16 id; NEXT_ARG(); if (get_u16(&id, *argv, 0)) { fprintf(stderr, "Illegal \"id\"\n"); goto ctrl_done; } addattr_l(nlh, 128, CTRL_ATTR_FAMILY_ID, &id, 2); } else { fprintf(stderr, "Wrong params\n"); goto ctrl_done; } if (rtnl_talk(&rth, nlh, nlh, sizeof(req)) < 0) { fprintf(stderr, "Error talking to the kernel\n"); goto ctrl_done; } if (print_ctrl2(NULL, nlh, (void *) stdout) < 0) { fprintf(stderr, "Dump terminated\n"); goto ctrl_done; } } if (cmd == CTRL_CMD_UNSPEC) { nlh->nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; nlh->nlmsg_seq = rth.dump = ++rth.seq; if (rtnl_send(&rth, nlh, nlh->nlmsg_len) < 0) { perror("Failed to send dump request\n"); goto ctrl_done; } rtnl_dump_filter(&rth, print_ctrl2, stdout); } ret = 0; ctrl_done: rtnl_close(&rth); return ret; }
static int seg6_do_cmd(void) { SEG6_REQUEST(req, 1024, opts.cmd, NLM_F_REQUEST); int repl = 0, dump = 0; if (genl_family < 0) { if (rtnl_open_byproto(&grth, 0, NETLINK_GENERIC) < 0) { fprintf(stderr, "Cannot open generic netlink socket\n"); exit(1); } genl_family = genl_resolve_family(&grth, SEG6_GENL_NAME); if (genl_family < 0) exit(1); req.n.nlmsg_type = genl_family; } switch (opts.cmd) { case SEG6_CMD_SETHMAC: { addattr32(&req.n, sizeof(req), SEG6_ATTR_HMACKEYID, opts.keyid); addattr8(&req.n, sizeof(req), SEG6_ATTR_SECRETLEN, strlen(opts.pass)); addattr8(&req.n, sizeof(req), SEG6_ATTR_ALGID, opts.alg_id); if (strlen(opts.pass)) addattr_l(&req.n, sizeof(req), SEG6_ATTR_SECRET, opts.pass, strlen(opts.pass)); break; } case SEG6_CMD_SET_TUNSRC: addattr_l(&req.n, sizeof(req), SEG6_ATTR_DST, &opts.addr, sizeof(struct in6_addr)); break; case SEG6_CMD_DUMPHMAC: dump = 1; break; case SEG6_CMD_GET_TUNSRC: repl = 1; break; } if (!repl && !dump) { if (rtnl_talk(&grth, &req.n, NULL, 0) < 0) return -1; } else if (repl) { if (rtnl_talk(&grth, &req.n, &req.n, sizeof(req)) < 0) return -2; if (process_msg(NULL, &req.n, stdout) < 0) { fprintf(stderr, "Error parsing reply\n"); exit(1); } } else { req.n.nlmsg_flags |= NLM_F_DUMP; req.n.nlmsg_seq = grth.dump = ++grth.seq; if (rtnl_send(&grth, &req, req.n.nlmsg_len) < 0) { perror("Failed to send dump request"); exit(1); } if (rtnl_dump_filter(&grth, process_msg, stdout) < 0) { fprintf(stderr, "Dump terminated\n"); exit(1); } } return 0; }
static int ctrl_list(int cmd, int argc, char **argv) { struct rtnl_handle rth; int ret = -1; char d[GENL_NAMSIZ]; struct { struct nlmsghdr n; struct genlmsghdr g; char buf[4096]; } req = { .n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN), .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK, .n.nlmsg_type = GENL_ID_CTRL, .g.cmd = CTRL_CMD_GETFAMILY, }; struct nlmsghdr *nlh = &req.n; if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) { fprintf(stderr, "Cannot open generic netlink socket\n"); exit(1); } if (cmd == CTRL_CMD_GETFAMILY) { if (argc != 2) { fprintf(stderr, "Wrong number of params\n"); return -1; } if (matches(*argv, "name") == 0) { NEXT_ARG(); strncpy(d, *argv, sizeof (d) - 1); addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME, d, strlen(d) + 1); } else if (matches(*argv, "id") == 0) { __u16 id; NEXT_ARG(); if (get_u16(&id, *argv, 0)) { fprintf(stderr, "Illegal \"id\"\n"); goto ctrl_done; } addattr_l(nlh, 128, CTRL_ATTR_FAMILY_ID, &id, 2); } else { fprintf(stderr, "Wrong params\n"); goto ctrl_done; } if (rtnl_talk(&rth, nlh, nlh, sizeof(req)) < 0) { fprintf(stderr, "Error talking to the kernel\n"); goto ctrl_done; } if (print_ctrl2(NULL, nlh, (void *) stdout) < 0) { fprintf(stderr, "Dump terminated\n"); goto ctrl_done; } } if (cmd == CTRL_CMD_UNSPEC) { nlh->nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; nlh->nlmsg_seq = rth.dump = ++rth.seq; if (rtnl_send(&rth, nlh, nlh->nlmsg_len) < 0) { perror("Failed to send dump request\n"); goto ctrl_done; } rtnl_dump_filter(&rth, print_ctrl2, stdout); } ret = 0; ctrl_done: rtnl_close(&rth); return ret; } static int ctrl_listen(int argc, char **argv) { struct rtnl_handle rth; if (rtnl_open_byproto(&rth, nl_mgrp(GENL_ID_CTRL), NETLINK_GENERIC) < 0) { fprintf(stderr, "Canot open generic netlink socket\n"); return -1; } if (rtnl_listen(&rth, print_ctrl, (void *) stdout) < 0) return -1; return 0; } static int parse_ctrl(struct genl_util *a, int argc, char **argv) { argv++; if (--argc <= 0) { fprintf(stderr, "wrong controller params\n"); return -1; } if (matches(*argv, "monitor") == 0) return ctrl_listen(argc-1, argv+1); if (matches(*argv, "get") == 0) return ctrl_list(CTRL_CMD_GETFAMILY, argc-1, argv+1); if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0 || matches(*argv, "lst") == 0) return ctrl_list(CTRL_CMD_UNSPEC, argc-1, argv+1); if (matches(*argv, "help") == 0) return usage(); fprintf(stderr, "ctrl command \"%s\" is unknown, try \"ctrl help\".\n", *argv); return -1; }