static int do_add(int argc, char **argv) { struct l2tp_parm p; int ret = 0; if (parse_args(argc, argv, L2TP_ADD, &p) < 0) return -1; if (!p.tunnel && !p.session) missarg("tunnel or session"); if (p.tunnel_id == 0) missarg("tunnel_id"); /* session_id and peer_session_id must be provided for sessions */ if ((p.session) && (p.peer_session_id == 0)) missarg("peer_session_id"); if ((p.session) && (p.session_id == 0)) missarg("session_id"); /* peer_tunnel_id is needed for tunnels */ if ((p.tunnel) && (p.peer_tunnel_id == 0)) missarg("peer_tunnel_id"); if (p.tunnel) { if (p.local_ip.family == AF_UNSPEC) missarg("local"); if (p.peer_ip.family == AF_UNSPEC) missarg("remote"); if (p.encap == L2TP_ENCAPTYPE_UDP) { if (p.local_udp_port == 0) missarg("udp_sport"); if (p.peer_udp_port == 0) missarg("udp_dport"); } ret = create_tunnel(&p); } if (p.session) { /* Only ethernet pseudowires supported */ p.pw_type = L2TP_PWTYPE_ETH; ret = create_session(&p); } return ret; }
static int do_del(int argc, char **argv) { struct l2tp_parm p; if (parse_args(argc, argv, L2TP_DEL, &p) < 0) return -1; if (!p.tunnel && !p.session) missarg("tunnel or session"); if ((p.tunnel) && (p.tunnel_id == 0)) missarg("tunnel_id"); if ((p.session) && (p.session_id == 0)) missarg("session_id"); if (p.session_id) return delete_session(&p); else return delete_tunnel(&p); return -1; }
static int xfrm_tmpl_parse(struct xfrm_user_tmpl *tmpl, int *argcp, char ***argvp) { int argc = *argcp; char **argv = *argvp; char *idp = NULL; while (1) { if (strcmp(*argv, "mode") == 0) { NEXT_ARG(); xfrm_mode_parse(&tmpl->mode, &argc, &argv); } else if (strcmp(*argv, "reqid") == 0) { NEXT_ARG(); xfrm_reqid_parse(&tmpl->reqid, &argc, &argv); } else if (strcmp(*argv, "level") == 0) { NEXT_ARG(); if (strcmp(*argv, "required") == 0) tmpl->optional = 0; else if (strcmp(*argv, "use") == 0) tmpl->optional = 1; else invarg("\"LEVEL\" is invalid\n", *argv); } else { if (idp) { PREV_ARG(); /* back track */ break; } idp = *argv; xfrm_id_parse(&tmpl->saddr, &tmpl->id, &tmpl->family, 0, &argc, &argv); if (preferred_family == AF_UNSPEC) preferred_family = tmpl->family; } if (!NEXT_ARG_OK()) break; NEXT_ARG(); } if (argc == *argcp) missarg("TMPL"); *argcp = argc; *argvp = argv; return 0; }
static int do_show(int argc, char **argv) { struct l2tp_data data; struct l2tp_parm *p = &data.config; if (parse_args(argc, argv, L2TP_GET, p) < 0) return -1; if (!p->tunnel && !p->session) missarg("tunnel or session"); if (p->session) get_session(&data); else get_tunnel(&data); return 0; }
int xfrm_id_parse(xfrm_address_t *saddr, struct xfrm_id *id, __u16 *family, int loose, int *argcp, char ***argvp) { int argc = *argcp; char **argv = *argvp; inet_prefix dst; inet_prefix src; memset(&dst, 0, sizeof(dst)); memset(&src, 0, sizeof(src)); while (1) { if (strcmp(*argv, "src") == 0) { NEXT_ARG(); get_prefix(&src, *argv, preferred_family); if (src.family == AF_UNSPEC) invarg("\"src\" address family is AF_UNSPEC", *argv); if (family) *family = src.family; memcpy(saddr, &src.data, sizeof(*saddr)); filter.id_src_mask = src.bitlen; } else if (strcmp(*argv, "dst") == 0) { NEXT_ARG(); get_prefix(&dst, *argv, preferred_family); if (dst.family == AF_UNSPEC) invarg("\"dst\" address family is AF_UNSPEC", *argv); if (family) *family = dst.family; memcpy(&id->daddr, &dst.data, sizeof(id->daddr)); filter.id_dst_mask = dst.bitlen; } else if (strcmp(*argv, "proto") == 0) { int ret; NEXT_ARG(); ret = xfrm_xfrmproto_getbyname(*argv); if (ret < 0) invarg("\"XFRM_PROTO\" is invalid", *argv); id->proto = (__u8)ret; filter.id_proto_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "spi") == 0) { __u32 spi; NEXT_ARG(); if (get_u32(&spi, *argv, 0)) invarg("\"SPI\" is invalid", *argv); spi = htonl(spi); id->spi = spi; filter.id_spi_mask = XFRM_FILTER_MASK_FULL; } else { PREV_ARG(); /* back track */ break; } if (!NEXT_ARG_OK()) break; NEXT_ARG(); } if (src.family && dst.family && (src.family != dst.family)) invarg("the same address family is required between \"src\" and \"dst\"", *argv); if (loose == 0 && id->proto == 0) missarg("XFRM_PROTO"); if (argc == *argcp) missarg("ID"); *argcp = argc; *argvp = argv; return 0; }
static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv) { struct rtnl_handle rth; struct { struct nlmsghdr n; struct xfrm_usersa_info xsinfo; char buf[RTA_BUF_SIZE]; } req; struct xfrm_replay_state replay; char *idp = NULL; char *aeadop = NULL; char *ealgop = NULL; char *aalgop = NULL; char *calgop = NULL; char *coap = NULL; char *sctxp = NULL; struct xfrm_mark mark = {0, 0}; struct { struct xfrm_user_sec_ctx sctx; char str[CTX_BUF_SIZE]; } ctx; memset(&req, 0, sizeof(req)); memset(&replay, 0, sizeof(replay)); memset(&ctx, 0, sizeof(ctx)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsinfo)); req.n.nlmsg_flags = NLM_F_REQUEST|flags; req.n.nlmsg_type = cmd; req.xsinfo.family = preferred_family; req.xsinfo.lft.soft_byte_limit = XFRM_INF; req.xsinfo.lft.hard_byte_limit = XFRM_INF; req.xsinfo.lft.soft_packet_limit = XFRM_INF; req.xsinfo.lft.hard_packet_limit = XFRM_INF; while (argc > 0) { if (strcmp(*argv, "mode") == 0) { NEXT_ARG(); xfrm_mode_parse(&req.xsinfo.mode, &argc, &argv); } else if (strcmp(*argv, "mark") == 0) { xfrm_parse_mark(&mark, &argc, &argv); } else if (strcmp(*argv, "reqid") == 0) { NEXT_ARG(); xfrm_reqid_parse(&req.xsinfo.reqid, &argc, &argv); } else if (strcmp(*argv, "seq") == 0) { NEXT_ARG(); xfrm_seq_parse(&req.xsinfo.seq, &argc, &argv); } else if (strcmp(*argv, "replay-window") == 0) { NEXT_ARG(); if (get_u8(&req.xsinfo.replay_window, *argv, 0)) invarg("\"replay-window\" value is invalid", *argv); } else if (strcmp(*argv, "replay-seq") == 0) { NEXT_ARG(); if (get_u32(&replay.seq, *argv, 0)) invarg("\"replay-seq\" value is invalid", *argv); } else if (strcmp(*argv, "replay-oseq") == 0) { NEXT_ARG(); if (get_u32(&replay.oseq, *argv, 0)) invarg("\"replay-oseq\" value is invalid", *argv); } else if (strcmp(*argv, "flag") == 0) { NEXT_ARG(); xfrm_state_flag_parse(&req.xsinfo.flags, &argc, &argv); } else if (strcmp(*argv, "sel") == 0) { NEXT_ARG(); xfrm_selector_parse(&req.xsinfo.sel, &argc, &argv); } else if (strcmp(*argv, "limit") == 0) { NEXT_ARG(); xfrm_lifetime_cfg_parse(&req.xsinfo.lft, &argc, &argv); } else if (strcmp(*argv, "encap") == 0) { struct xfrm_encap_tmpl encap; inet_prefix oa; NEXT_ARG(); xfrm_encap_type_parse(&encap.encap_type, &argc, &argv); NEXT_ARG(); if (get_u16(&encap.encap_sport, *argv, 0)) invarg("\"encap\" sport value is invalid", *argv); encap.encap_sport = htons(encap.encap_sport); NEXT_ARG(); if (get_u16(&encap.encap_dport, *argv, 0)) invarg("\"encap\" dport value is invalid", *argv); encap.encap_dport = htons(encap.encap_dport); NEXT_ARG(); get_addr(&oa, *argv, AF_UNSPEC); memcpy(&encap.encap_oa, &oa.data, sizeof(encap.encap_oa)); addattr_l(&req.n, sizeof(req.buf), XFRMA_ENCAP, (void *)&encap, sizeof(encap)); } else if (strcmp(*argv, "coa") == 0) { inet_prefix coa; xfrm_address_t xcoa; if (coap) duparg("coa", *argv); coap = *argv; NEXT_ARG(); get_prefix(&coa, *argv, preferred_family); if (coa.family == AF_UNSPEC) invarg("\"coa\" address family is AF_UNSPEC", *argv); if (coa.bytelen > sizeof(xcoa)) invarg("\"coa\" address length is too large", *argv); memset(&xcoa, 0, sizeof(xcoa)); memcpy(&xcoa, &coa.data, coa.bytelen); addattr_l(&req.n, sizeof(req.buf), XFRMA_COADDR, (void *)&xcoa, sizeof(xcoa)); } else if (strcmp(*argv, "ctx") == 0) { char *context; if (sctxp) duparg("ctx", *argv); sctxp = *argv; NEXT_ARG(); context = *argv; xfrm_sctx_parse((char *)&ctx.str, context, &ctx.sctx); addattr_l(&req.n, sizeof(req.buf), XFRMA_SEC_CTX, (void *)&ctx, ctx.sctx.len); } else { /* try to assume ALGO */ int type = xfrm_algotype_getbyname(*argv); switch (type) { case XFRMA_ALG_AEAD: case XFRMA_ALG_CRYPT: case XFRMA_ALG_AUTH: case XFRMA_ALG_AUTH_TRUNC: case XFRMA_ALG_COMP: { /* ALGO */ struct { union { struct xfrm_algo alg; struct xfrm_algo_aead aead; struct xfrm_algo_auth auth; } u; char buf[XFRM_ALGO_KEY_BUF_SIZE]; } alg = {}; int len; __u32 icvlen, trunclen; char *name; char *key; char *buf; switch (type) { case XFRMA_ALG_AEAD: if (aeadop) duparg("ALGO-TYPE", *argv); aeadop = *argv; break; case XFRMA_ALG_CRYPT: if (ealgop) duparg("ALGO-TYPE", *argv); ealgop = *argv; break; case XFRMA_ALG_AUTH: case XFRMA_ALG_AUTH_TRUNC: if (aalgop) duparg("ALGO-TYPE", *argv); aalgop = *argv; break; case XFRMA_ALG_COMP: if (calgop) duparg("ALGO-TYPE", *argv); calgop = *argv; break; default: /* not reached */ invarg("\"ALGO-TYPE\" is invalid\n", *argv); } if (!NEXT_ARG_OK()) missarg("ALGO-NAME"); NEXT_ARG(); name = *argv; if (!NEXT_ARG_OK()) missarg("ALGO-KEY"); NEXT_ARG(); key = *argv; buf = alg.u.alg.alg_key; len = sizeof(alg.u.alg); switch (type) { case XFRMA_ALG_AEAD: if (!NEXT_ARG_OK()) missarg("ALGO-ICV-LEN"); NEXT_ARG(); if (get_u32(&icvlen, *argv, 0)) invarg("\"aead\" ICV length is invalid", *argv); alg.u.aead.alg_icv_len = icvlen; buf = alg.u.aead.alg_key; len = sizeof(alg.u.aead); break; case XFRMA_ALG_AUTH_TRUNC: if (!NEXT_ARG_OK()) missarg("ALGO-TRUNC-LEN"); NEXT_ARG(); if (get_u32(&trunclen, *argv, 0)) invarg("\"auth\" trunc length is invalid", *argv); alg.u.auth.alg_trunc_len = trunclen; buf = alg.u.auth.alg_key; len = sizeof(alg.u.auth); break; } xfrm_algo_parse((void *)&alg, type, name, key, buf, sizeof(alg.buf)); len += alg.u.alg.alg_key_len; addattr_l(&req.n, sizeof(req.buf), type, (void *)&alg, len); break; } default: /* try to assume ID */ if (idp) invarg("unknown", *argv); idp = *argv; /* ID */ xfrm_id_parse(&req.xsinfo.saddr, &req.xsinfo.id, &req.xsinfo.family, 0, &argc, &argv); if (preferred_family == AF_UNSPEC) preferred_family = req.xsinfo.family; } } argc--; argv++; } if (replay.seq || replay.oseq) addattr_l(&req.n, sizeof(req.buf), XFRMA_REPLAY_VAL, (void *)&replay, sizeof(replay)); if (!idp) { fprintf(stderr, "Not enough information: \"ID\" is required\n"); exit(1); } if (mark.m & mark.v) { int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK, (void *)&mark, sizeof(mark)); if (r < 0) { fprintf(stderr, "XFRMA_MARK failed\n"); exit(1); } } switch (req.xsinfo.mode) { case XFRM_MODE_TRANSPORT: case XFRM_MODE_TUNNEL: if (!xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) { fprintf(stderr, "\"mode\" is invalid with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } break; case XFRM_MODE_ROUTEOPTIMIZATION: case XFRM_MODE_IN_TRIGGER: if (!xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) { fprintf(stderr, "\"mode\" is invalid with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } if (req.xsinfo.id.spi != 0) { fprintf(stderr, "\"spi\" must be 0 with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } break; default: break; } if (aeadop || ealgop || aalgop || calgop) { if (!xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) { fprintf(stderr, "\"ALGO\" is invalid with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } } else { if (xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) { fprintf(stderr, "\"ALGO\" is required with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit (1); } } if (coap) { if (!xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) { fprintf(stderr, "\"coa\" is invalid with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } } else { if (xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) { fprintf(stderr, "\"coa\" is required with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit (1); } } if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) exit(1); if (req.xsinfo.family == AF_UNSPEC) req.xsinfo.family = AF_INET; if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) exit(2); rtnl_close(&rth); return 0; }
static int xfrm_selector_upspec_parse(struct xfrm_selector *sel, int *argcp, char ***argvp) { int argc = *argcp; char **argv = *argvp; char *sportp = NULL; char *dportp = NULL; char *typep = NULL; char *codep = NULL; while (1) { if (strcmp(*argv, "proto") == 0) { __u8 upspec; NEXT_ARG(); if (strcmp(*argv, "any") == 0) upspec = 0; else { struct protoent *pp; pp = getprotobyname(*argv); if (pp) upspec = pp->p_proto; else { if (get_u8(&upspec, *argv, 0)) invarg("\"PROTO\" is invalid", *argv); } } sel->proto = upspec; filter.upspec_proto_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "sport") == 0) { sportp = *argv; NEXT_ARG(); if (get_u16(&sel->sport, *argv, 0)) invarg("\"PORT\" is invalid", *argv); sel->sport = htons(sel->sport); if (sel->sport) sel->sport_mask = ~((__u16)0); filter.upspec_sport_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "dport") == 0) { dportp = *argv; NEXT_ARG(); if (get_u16(&sel->dport, *argv, 0)) invarg("\"PORT\" is invalid", *argv); sel->dport = htons(sel->dport); if (sel->dport) sel->dport_mask = ~((__u16)0); filter.upspec_dport_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "type") == 0) { typep = *argv; NEXT_ARG(); if (get_u16(&sel->sport, *argv, 0) || (sel->sport & ~((__u16)0xff))) invarg("\"type\" value is invalid", *argv); sel->sport = htons(sel->sport); sel->sport_mask = ~((__u16)0); filter.upspec_sport_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "code") == 0) { codep = *argv; NEXT_ARG(); if (get_u16(&sel->dport, *argv, 0) || (sel->dport & ~((__u16)0xff))) invarg("\"code\" value is invalid", *argv); sel->dport = htons(sel->dport); sel->dport_mask = ~((__u16)0); filter.upspec_dport_mask = XFRM_FILTER_MASK_FULL; } else { PREV_ARG(); /* back track */ break; } if (!NEXT_ARG_OK()) break; NEXT_ARG(); } if (argc == *argcp) missarg("UPSPEC"); if (sportp || dportp) { switch (sel->proto) { case IPPROTO_TCP: case IPPROTO_UDP: case IPPROTO_SCTP: case IPPROTO_DCCP: break; default: fprintf(stderr, "\"sport\" and \"dport\" are invalid with proto=%s\n", strxf_proto(sel->proto)); exit(1); } } if (typep || codep) { switch (sel->proto) { case IPPROTO_ICMP: case IPPROTO_ICMPV6: case IPPROTO_MH: break; default: fprintf(stderr, "\"type\" and \"code\" are invalid with proto=%s\n", strxf_proto(sel->proto)); exit(1); } } *argcp = argc; *argvp = argv; return 0; }
int xfrm_selector_parse(struct xfrm_selector *sel, int *argcp, char ***argvp) { int argc = *argcp; char **argv = *argvp; inet_prefix dst; inet_prefix src; char *upspecp = NULL; memset(&dst, 0, sizeof(dst)); memset(&src, 0, sizeof(src)); while (1) { if (strcmp(*argv, "src") == 0) { NEXT_ARG(); get_prefix(&src, *argv, preferred_family); if (src.family == AF_UNSPEC) invarg("\"src\" address family is AF_UNSPEC", *argv); sel->family = src.family; memcpy(&sel->saddr, &src.data, sizeof(sel->saddr)); sel->prefixlen_s = src.bitlen; filter.sel_src_mask = src.bitlen; } else if (strcmp(*argv, "dst") == 0) { NEXT_ARG(); get_prefix(&dst, *argv, preferred_family); if (dst.family == AF_UNSPEC) invarg("\"dst\" address family is AF_UNSPEC", *argv); sel->family = dst.family; memcpy(&sel->daddr, &dst.data, sizeof(sel->daddr)); sel->prefixlen_d = dst.bitlen; filter.sel_dst_mask = dst.bitlen; } else if (strcmp(*argv, "dev") == 0) { int ifindex; NEXT_ARG(); if (strcmp(*argv, "none") == 0) ifindex = 0; else { ifindex = ll_name_to_index(*argv); if (ifindex <= 0) invarg("\"DEV\" is invalid", *argv); } sel->ifindex = ifindex; filter.sel_dev_mask = XFRM_FILTER_MASK_FULL; } else { if (upspecp) { PREV_ARG(); /* back track */ break; } else { upspecp = *argv; xfrm_selector_upspec_parse(sel, &argc, &argv); } } if (!NEXT_ARG_OK()) break; NEXT_ARG(); } if (src.family && dst.family && (src.family != dst.family)) invarg("the same address family is required between \"src\" and \"dst\"", *argv); if (argc == *argcp) missarg("SELECTOR"); *argcp = argc; *argvp = argv; return 0; }
int iplink_parse(int argc, char **argv, struct iplink_req *req, char **name, char **type, char **link, char **dev, int *group, int *index) { int ret, len; char abuf[32]; int qlen = -1; int mtu = -1; int netns = -1; int vf = -1; int numtxqueues = -1; int numrxqueues = -1; int dev_index = 0; *group = -1; ret = argc; while (argc > 0) { if (strcmp(*argv, "up") == 0) { req->i.ifi_change |= IFF_UP; req->i.ifi_flags |= IFF_UP; } else if (strcmp(*argv, "down") == 0) { req->i.ifi_change |= IFF_UP; req->i.ifi_flags &= ~IFF_UP; } else if (strcmp(*argv, "name") == 0) { NEXT_ARG(); *name = *argv; } else if (strcmp(*argv, "index") == 0) { NEXT_ARG(); *index = atoi(*argv); } else if (matches(*argv, "link") == 0) { NEXT_ARG(); *link = *argv; } else if (matches(*argv, "address") == 0) { NEXT_ARG(); len = ll_addr_a2n(abuf, sizeof(abuf), *argv); if (len < 0) return -1; addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, len); } else if (matches(*argv, "broadcast") == 0 || strcmp(*argv, "brd") == 0) { NEXT_ARG(); len = ll_addr_a2n(abuf, sizeof(abuf), *argv); if (len < 0) return -1; addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len); } else if (matches(*argv, "txqueuelen") == 0 || strcmp(*argv, "qlen") == 0 || matches(*argv, "txqlen") == 0) { NEXT_ARG(); if (qlen != -1) duparg("txqueuelen", *argv); if (get_integer(&qlen, *argv, 0)) invarg("Invalid \"txqueuelen\" value\n", *argv); addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4); } else if (strcmp(*argv, "mtu") == 0) { NEXT_ARG(); if (mtu != -1) duparg("mtu", *argv); if (get_integer(&mtu, *argv, 0)) invarg("Invalid \"mtu\" value\n", *argv); addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4); } else if (strcmp(*argv, "netns") == 0) { NEXT_ARG(); if (netns != -1) duparg("netns", *argv); if ((netns = get_netns_fd(*argv)) >= 0) addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD, &netns, 4); else if (get_integer(&netns, *argv, 0) == 0) addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4); else invarg("Invalid \"netns\" value\n", *argv); } else if (strcmp(*argv, "multicast") == 0) { NEXT_ARG(); req->i.ifi_change |= IFF_MULTICAST; if (strcmp(*argv, "on") == 0) { req->i.ifi_flags |= IFF_MULTICAST; } else if (strcmp(*argv, "off") == 0) { req->i.ifi_flags &= ~IFF_MULTICAST; } else return on_off("multicast", *argv); } else if (strcmp(*argv, "allmulticast") == 0) { NEXT_ARG(); req->i.ifi_change |= IFF_ALLMULTI; if (strcmp(*argv, "on") == 0) { req->i.ifi_flags |= IFF_ALLMULTI; } else if (strcmp(*argv, "off") == 0) { req->i.ifi_flags &= ~IFF_ALLMULTI; } else return on_off("allmulticast", *argv); } else if (strcmp(*argv, "promisc") == 0) { NEXT_ARG(); req->i.ifi_change |= IFF_PROMISC; if (strcmp(*argv, "on") == 0) { req->i.ifi_flags |= IFF_PROMISC; } else if (strcmp(*argv, "off") == 0) { req->i.ifi_flags &= ~IFF_PROMISC; } else return on_off("promisc", *argv); } else if (strcmp(*argv, "trailers") == 0) { NEXT_ARG(); req->i.ifi_change |= IFF_NOTRAILERS; if (strcmp(*argv, "off") == 0) { req->i.ifi_flags |= IFF_NOTRAILERS; } else if (strcmp(*argv, "on") == 0) { req->i.ifi_flags &= ~IFF_NOTRAILERS; } else return on_off("trailers", *argv); } else if (strcmp(*argv, "arp") == 0) { NEXT_ARG(); req->i.ifi_change |= IFF_NOARP; if (strcmp(*argv, "on") == 0) { req->i.ifi_flags &= ~IFF_NOARP; } else if (strcmp(*argv, "off") == 0) { req->i.ifi_flags |= IFF_NOARP; } else return on_off("noarp", *argv); } else if (strcmp(*argv, "vf") == 0) { struct rtattr *vflist; NEXT_ARG(); if (get_integer(&vf, *argv, 0)) { invarg("Invalid \"vf\" value\n", *argv); } vflist = addattr_nest(&req->n, sizeof(*req), IFLA_VFINFO_LIST); if (dev_index == 0) missarg("dev"); len = iplink_parse_vf(vf, &argc, &argv, req, dev_index); if (len < 0) return -1; addattr_nest_end(&req->n, vflist); } else if (matches(*argv, "master") == 0) { int ifindex; NEXT_ARG(); ifindex = ll_name_to_index(*argv); if (!ifindex) invarg("Device does not exist\n", *argv); addattr_l(&req->n, sizeof(*req), IFLA_MASTER, &ifindex, 4); } else if (matches(*argv, "nomaster") == 0) { int ifindex = 0; addattr_l(&req->n, sizeof(*req), IFLA_MASTER, &ifindex, 4); } else if (matches(*argv, "dynamic") == 0) { NEXT_ARG(); req->i.ifi_change |= IFF_DYNAMIC; if (strcmp(*argv, "on") == 0) { req->i.ifi_flags |= IFF_DYNAMIC; } else if (strcmp(*argv, "off") == 0) { req->i.ifi_flags &= ~IFF_DYNAMIC; } else return on_off("dynamic", *argv); } else if (matches(*argv, "type") == 0) { NEXT_ARG(); *type = *argv; argc--; argv++; break; } else if (matches(*argv, "alias") == 0) { NEXT_ARG(); addattr_l(&req->n, sizeof(*req), IFLA_IFALIAS, *argv, strlen(*argv)); argc--; argv++; break; } else if (strcmp(*argv, "group") == 0) { NEXT_ARG(); if (*group != -1) duparg("group", *argv); if (rtnl_group_a2n(group, *argv)) invarg("Invalid \"group\" value\n", *argv); } else if (strcmp(*argv, "mode") == 0) { int mode; NEXT_ARG(); mode = get_link_mode(*argv); if (mode < 0) invarg("Invalid link mode\n", *argv); addattr8(&req->n, sizeof(*req), IFLA_LINKMODE, mode); } else if (strcmp(*argv, "state") == 0) { int state; NEXT_ARG(); state = get_operstate(*argv); if (state < 0) invarg("Invalid operstate\n", *argv); addattr8(&req->n, sizeof(*req), IFLA_OPERSTATE, state); } else if (matches(*argv, "numtxqueues") == 0) { NEXT_ARG(); if (numtxqueues != -1) duparg("numtxqueues", *argv); if (get_integer(&numtxqueues, *argv, 0)) invarg("Invalid \"numtxqueues\" value\n", *argv); addattr_l(&req->n, sizeof(*req), IFLA_NUM_TX_QUEUES, &numtxqueues, 4); } else if (matches(*argv, "numrxqueues") == 0) { NEXT_ARG(); if (numrxqueues != -1) duparg("numrxqueues", *argv); if (get_integer(&numrxqueues, *argv, 0)) invarg("Invalid \"numrxqueues\" value\n", *argv); addattr_l(&req->n, sizeof(*req), IFLA_NUM_RX_QUEUES, &numrxqueues, 4); } else { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); } if (matches(*argv, "help") == 0) usage(); if (*dev) duparg2("dev", *argv); *dev = *argv; dev_index = ll_name_to_index(*dev); if (dev_index == 0) invarg("Unknown device", *argv); } argc--; argv++; } return ret - argc; }
int xfrm_id_parse(xfrm_address_t *saddr, struct xfrm_id *id, __u16 *family, int loose, int *argcp, char ***argvp) { int argc = *argcp; char **argv = *argvp; inet_prefix dst; inet_prefix src; memset(&dst, 0, sizeof(dst)); memset(&src, 0, sizeof(src)); while (1) { if (strcmp(*argv, "src") == 0) { NEXT_ARG(); get_prefix(&src, *argv, preferred_family); if (src.family == AF_UNSPEC) invarg("value after \"src\" has an unrecognized address family", *argv); if (family) *family = src.family; memcpy(saddr, &src.data, sizeof(*saddr)); filter.id_src_mask = src.bitlen; } else if (strcmp(*argv, "dst") == 0) { NEXT_ARG(); get_prefix(&dst, *argv, preferred_family); if (dst.family == AF_UNSPEC) invarg("value after \"dst\" has an unrecognized address family", *argv); if (family) *family = dst.family; memcpy(&id->daddr, &dst.data, sizeof(id->daddr)); filter.id_dst_mask = dst.bitlen; } else if (strcmp(*argv, "proto") == 0) { int ret; NEXT_ARG(); ret = xfrm_xfrmproto_getbyname(*argv); if (ret < 0) invarg("XFRM-PROTO value is invalid", *argv); id->proto = (__u8)ret; filter.id_proto_mask = XFRM_FILTER_MASK_FULL; } else if (strcmp(*argv, "spi") == 0) { __u32 spi; NEXT_ARG(); if (get_u32(&spi, *argv, 0)) invarg("SPI value is invalid", *argv); spi = htonl(spi); id->spi = spi; filter.id_spi_mask = XFRM_FILTER_MASK_FULL; } else { PREV_ARG(); /* back track */ break; } if (!NEXT_ARG_OK()) break; NEXT_ARG(); } if (src.family && dst.family && (src.family != dst.family)) invarg("the same address family is required between values after \"src\" and \"dst\"", *argv); if (id->spi && id->proto) { if (xfrm_xfrmproto_is_ro(id->proto)) { fprintf(stderr, "\"spi\" is invalid with XFRM-PROTO value \"%s\"\n", strxf_xfrmproto(id->proto)); exit(1); } else if (id->proto == IPPROTO_COMP && ntohl(id->spi) >= 0x10000) { fprintf(stderr, "SPI value is too large with XFRM-PROTO value \"%s\"\n", strxf_xfrmproto(id->proto)); exit(1); } } if (loose == 0 && id->proto == 0) missarg("XFRM-PROTO"); if (argc == *argcp) missarg("ID"); *argcp = argc; *argvp = argv; return 0; }
static int ipntable_modify(int cmd, int flags, int argc, char **argv) { struct { struct nlmsghdr n; struct ndtmsg ndtm; char buf[1024]; } req; char *namep = NULL; char *threshsp = NULL; char *gc_intp = NULL; char parms_buf[1024]; struct rtattr *parms_rta = (struct rtattr *)parms_buf; int parms_change = 0; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST|flags; req.n.nlmsg_type = cmd; req.ndtm.ndtm_family = preferred_family; req.ndtm.ndtm_pad1 = 0; req.ndtm.ndtm_pad2 = 0; memset(&parms_buf, 0, sizeof(parms_buf)); parms_rta->rta_type = NDTA_PARMS; parms_rta->rta_len = RTA_LENGTH(0); while (argc > 0) { if (strcmp(*argv, "name") == 0) { int len; NEXT_ARG(); if (namep) duparg("NAME", *argv); namep = *argv; len = strlen(namep) + 1; addattr_l(&req.n, sizeof(req), NDTA_NAME, namep, len); } else if (strcmp(*argv, "thresh1") == 0) { __u32 thresh1; NEXT_ARG(); threshsp = *argv; if (get_u32(&thresh1, *argv, 0)) invarg("\"thresh1\" value is invalid", *argv); addattr32(&req.n, sizeof(req), NDTA_THRESH1, thresh1); } else if (strcmp(*argv, "thresh2") == 0) { __u32 thresh2; NEXT_ARG(); threshsp = *argv; if (get_u32(&thresh2, *argv, 0)) invarg("\"thresh2\" value is invalid", *argv); addattr32(&req.n, sizeof(req), NDTA_THRESH2, thresh2); } else if (strcmp(*argv, "thresh3") == 0) { __u32 thresh3; NEXT_ARG(); threshsp = *argv; if (get_u32(&thresh3, *argv, 0)) invarg("\"thresh3\" value is invalid", *argv); addattr32(&req.n, sizeof(req), NDTA_THRESH3, thresh3); } else if (strcmp(*argv, "gc_int") == 0) { __u64 gc_int; NEXT_ARG(); gc_intp = *argv; if (get_u64(&gc_int, *argv, 0)) invarg("\"gc_int\" value is invalid", *argv); addattr_l(&req.n, sizeof(req), NDTA_GC_INTERVAL, &gc_int, sizeof(gc_int)); } else if (strcmp(*argv, "dev") == 0) { __u32 ifindex; NEXT_ARG(); ifindex = ll_name_to_index(*argv); if (ifindex == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", *argv); return -1; } rta_addattr32(parms_rta, sizeof(parms_buf), NDTPA_IFINDEX, ifindex); } else if (strcmp(*argv, "base_reachable") == 0) { __u64 breachable; NEXT_ARG(); if (get_u64(&breachable, *argv, 0)) invarg("\"base_reachable\" value is invalid", *argv); rta_addattr_l(parms_rta, sizeof(parms_buf), NDTPA_BASE_REACHABLE_TIME, &breachable, sizeof(breachable)); parms_change = 1; } else if (strcmp(*argv, "retrans") == 0) { __u64 retrans; NEXT_ARG(); if (get_u64(&retrans, *argv, 0)) invarg("\"retrans\" value is invalid", *argv); rta_addattr_l(parms_rta, sizeof(parms_buf), NDTPA_RETRANS_TIME, &retrans, sizeof(retrans)); parms_change = 1; } else if (strcmp(*argv, "gc_stale") == 0) { __u64 gc_stale; NEXT_ARG(); if (get_u64(&gc_stale, *argv, 0)) invarg("\"gc_stale\" value is invalid", *argv); rta_addattr_l(parms_rta, sizeof(parms_buf), NDTPA_GC_STALETIME, &gc_stale, sizeof(gc_stale)); parms_change = 1; } else if (strcmp(*argv, "delay_probe") == 0) { __u64 delay_probe; NEXT_ARG(); if (get_u64(&delay_probe, *argv, 0)) invarg("\"delay_probe\" value is invalid", *argv); rta_addattr_l(parms_rta, sizeof(parms_buf), NDTPA_DELAY_PROBE_TIME, &delay_probe, sizeof(delay_probe)); parms_change = 1; } else if (strcmp(*argv, "queue") == 0) { __u32 queue; NEXT_ARG(); if (get_u32(&queue, *argv, 0)) invarg("\"queue\" value is invalid", *argv); if (!parms_rta) parms_rta = (struct rtattr *)&parms_buf; rta_addattr32(parms_rta, sizeof(parms_buf), NDTPA_QUEUE_LEN, queue); parms_change = 1; } else if (strcmp(*argv, "app_probes") == 0) { __u32 aprobe; NEXT_ARG(); if (get_u32(&aprobe, *argv, 0)) invarg("\"app_probes\" value is invalid", *argv); rta_addattr32(parms_rta, sizeof(parms_buf), NDTPA_APP_PROBES, aprobe); parms_change = 1; } else if (strcmp(*argv, "ucast_probes") == 0) { __u32 uprobe; NEXT_ARG(); if (get_u32(&uprobe, *argv, 0)) invarg("\"ucast_probes\" value is invalid", *argv); rta_addattr32(parms_rta, sizeof(parms_buf), NDTPA_UCAST_PROBES, uprobe); parms_change = 1; } else if (strcmp(*argv, "mcast_probes") == 0) { __u32 mprobe; NEXT_ARG(); if (get_u32(&mprobe, *argv, 0)) invarg("\"mcast_probes\" value is invalid", *argv); rta_addattr32(parms_rta, sizeof(parms_buf), NDTPA_MCAST_PROBES, mprobe); parms_change = 1; } else if (strcmp(*argv, "anycast_delay") == 0) { __u64 anycast_delay; NEXT_ARG(); if (get_u64(&anycast_delay, *argv, 0)) invarg("\"anycast_delay\" value is invalid", *argv); rta_addattr_l(parms_rta, sizeof(parms_buf), NDTPA_ANYCAST_DELAY, &anycast_delay, sizeof(anycast_delay)); parms_change = 1; } else if (strcmp(*argv, "proxy_delay") == 0) { __u64 proxy_delay; NEXT_ARG(); if (get_u64(&proxy_delay, *argv, 0)) invarg("\"proxy_delay\" value is invalid", *argv); rta_addattr_l(parms_rta, sizeof(parms_buf), NDTPA_PROXY_DELAY, &proxy_delay, sizeof(proxy_delay)); parms_change = 1; } else if (strcmp(*argv, "proxy_queue") == 0) { __u32 pqueue; NEXT_ARG(); if (get_u32(&pqueue, *argv, 0)) invarg("\"proxy_queue\" value is invalid", *argv); rta_addattr32(parms_rta, sizeof(parms_buf), NDTPA_PROXY_QLEN, pqueue); parms_change = 1; } else if (strcmp(*argv, "locktime") == 0) { __u64 locktime; NEXT_ARG(); if (get_u64(&locktime, *argv, 0)) invarg("\"locktime\" value is invalid", *argv); rta_addattr_l(parms_rta, sizeof(parms_buf), NDTPA_LOCKTIME, &locktime, sizeof(locktime)); parms_change = 1; } else { invarg("unknown", *argv); } argc--; argv++; } if (!namep) missarg("NAME"); if (!threshsp && !gc_intp && !parms_change) { fprintf(stderr, "Not enough information: changable attributes required.\n"); exit(-1); } if (parms_rta->rta_len > RTA_LENGTH(0)) { addattr_l(&req.n, sizeof(req), NDTA_PARMS, RTA_DATA(parms_rta), RTA_PAYLOAD(parms_rta)); } if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) exit(2); 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 xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv) { struct rtnl_handle rth; struct { struct nlmsghdr n; struct xfrm_usersa_info xsinfo; char buf[RTA_BUF_SIZE]; } req; char *idp = NULL; char *ealgop = NULL; char *aalgop = NULL; char *calgop = NULL; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsinfo)); req.n.nlmsg_flags = NLM_F_REQUEST|flags; req.n.nlmsg_type = cmd; req.xsinfo.family = preferred_family; req.xsinfo.lft.soft_byte_limit = XFRM_INF; req.xsinfo.lft.hard_byte_limit = XFRM_INF; req.xsinfo.lft.soft_packet_limit = XFRM_INF; req.xsinfo.lft.hard_packet_limit = XFRM_INF; while (argc > 0) { if (strcmp(*argv, "mode") == 0) { NEXT_ARG(); xfrm_mode_parse(&req.xsinfo.mode, &argc, &argv); } else if (strcmp(*argv, "reqid") == 0) { NEXT_ARG(); xfrm_reqid_parse(&req.xsinfo.reqid, &argc, &argv); } else if (strcmp(*argv, "seq") == 0) { NEXT_ARG(); xfrm_seq_parse(&req.xsinfo.seq, &argc, &argv); } else if (strcmp(*argv, "replay-window") == 0) { NEXT_ARG(); if (get_u8(&req.xsinfo.replay_window, *argv, 0)) invarg("\"replay-window\" value is invalid", *argv); } else if (strcmp(*argv, "flag") == 0) { NEXT_ARG(); xfrm_state_flag_parse(&req.xsinfo.flags, &argc, &argv); } else if (strcmp(*argv, "sel") == 0) { NEXT_ARG(); xfrm_selector_parse(&req.xsinfo.sel, &argc, &argv); } else if (strcmp(*argv, "limit") == 0) { NEXT_ARG(); xfrm_lifetime_cfg_parse(&req.xsinfo.lft, &argc, &argv); } else if (strcmp(*argv, "encap") == 0) { struct xfrm_encap_tmpl encap; inet_prefix oa; NEXT_ARG(); xfrm_encap_type_parse(&encap.encap_type, &argc, &argv); NEXT_ARG(); if (get_u16(&encap.encap_sport, *argv, 0)) invarg("\"encap\" sport value is invalid", *argv); encap.encap_sport = htons(encap.encap_sport); NEXT_ARG(); if (get_u16(&encap.encap_dport, *argv, 0)) invarg("\"encap\" dport value is invalid", *argv); encap.encap_dport = htons(encap.encap_dport); NEXT_ARG(); get_addr(&oa, *argv, AF_UNSPEC); memcpy(&encap.encap_oa, &oa.data, sizeof(encap.encap_oa)); addattr_l(&req.n, sizeof(req.buf), XFRMA_ENCAP, (void *)&encap, sizeof(encap)); } else { /* try to assume ALGO */ int type = xfrm_algotype_getbyname(*argv); switch (type) { case XFRMA_ALG_CRYPT: case XFRMA_ALG_AUTH: case XFRMA_ALG_COMP: { /* ALGO */ struct { struct xfrm_algo alg; char buf[XFRM_ALGO_KEY_BUF_SIZE]; } alg; int len; char *name; char *key; switch (type) { case XFRMA_ALG_CRYPT: if (ealgop) duparg("ALGOTYPE", *argv); ealgop = *argv; break; case XFRMA_ALG_AUTH: if (aalgop) duparg("ALGOTYPE", *argv); aalgop = *argv; break; case XFRMA_ALG_COMP: if (calgop) duparg("ALGOTYPE", *argv); calgop = *argv; break; default: /* not reached */ invarg("\"ALGOTYPE\" is invalid\n", *argv); } if (!NEXT_ARG_OK()) missarg("ALGONAME"); NEXT_ARG(); name = *argv; if (!NEXT_ARG_OK()) missarg("ALGOKEY"); NEXT_ARG(); key = *argv; memset(&alg, 0, sizeof(alg)); xfrm_algo_parse((void *)&alg, type, name, key, sizeof(alg.buf)); len = sizeof(struct xfrm_algo) + alg.alg.alg_key_len; addattr_l(&req.n, sizeof(req.buf), type, (void *)&alg, len); break; } default: /* try to assume ID */ if (idp) invarg("unknown", *argv); idp = *argv; /* ID */ xfrm_id_parse(&req.xsinfo.saddr, &req.xsinfo.id, &req.xsinfo.family, 0, &argc, &argv); if (preferred_family == AF_UNSPEC) preferred_family = req.xsinfo.family; } } argc--; argv++; } if (!idp) { // fprintf(stderr, "Not enough information: \"ID\" is required\n"); exit(1); } if (ealgop || aalgop || calgop) { if (req.xsinfo.id.proto != IPPROTO_ESP && req.xsinfo.id.proto != IPPROTO_AH && req.xsinfo.id.proto != IPPROTO_COMP) { // fprintf(stderr, "\"ALGO\" is invalid with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } } else { if (req.xsinfo.id.proto == IPPROTO_ESP || req.xsinfo.id.proto == IPPROTO_AH || req.xsinfo.id.proto == IPPROTO_COMP) { // fprintf(stderr, "\"ALGO\" is required with proto=%s\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit (1); } } if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) exit(1); if (req.xsinfo.family == AF_UNSPEC) req.xsinfo.family = AF_INET; if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) exit(2); rtnl_close(&rth); return 0; }
static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv) { struct rtnl_handle rth; struct { struct nlmsghdr n; struct xfrm_usersa_info xsinfo; char buf[RTA_BUF_SIZE]; } req; struct xfrm_replay_state replay; struct xfrm_replay_state_esn replay_esn; __u32 replay_window = 0; __u32 seq = 0, oseq = 0, seq_hi = 0, oseq_hi = 0; char *idp = NULL; char *aeadop = NULL; char *ealgop = NULL; char *aalgop = NULL; char *calgop = NULL; char *coap = NULL; char *sctxp = NULL; __u32 extra_flags = 0; struct xfrm_mark mark = {0, 0}; struct { struct xfrm_user_sec_ctx sctx; char str[CTX_BUF_SIZE]; } ctx; memset(&req, 0, sizeof(req)); memset(&replay, 0, sizeof(replay)); memset(&replay_esn, 0, sizeof(replay_esn)); memset(&ctx, 0, sizeof(ctx)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xsinfo)); req.n.nlmsg_flags = NLM_F_REQUEST|flags; req.n.nlmsg_type = cmd; req.xsinfo.family = preferred_family; req.xsinfo.lft.soft_byte_limit = XFRM_INF; req.xsinfo.lft.hard_byte_limit = XFRM_INF; req.xsinfo.lft.soft_packet_limit = XFRM_INF; req.xsinfo.lft.hard_packet_limit = XFRM_INF; while (argc > 0) { if (strcmp(*argv, "mode") == 0) { NEXT_ARG(); xfrm_mode_parse(&req.xsinfo.mode, &argc, &argv); } else if (strcmp(*argv, "mark") == 0) { xfrm_parse_mark(&mark, &argc, &argv); } else if (strcmp(*argv, "reqid") == 0) { NEXT_ARG(); xfrm_reqid_parse(&req.xsinfo.reqid, &argc, &argv); } else if (strcmp(*argv, "seq") == 0) { NEXT_ARG(); xfrm_seq_parse(&req.xsinfo.seq, &argc, &argv); } else if (strcmp(*argv, "replay-window") == 0) { NEXT_ARG(); if (get_u32(&replay_window, *argv, 0)) invarg("value after \"replay-window\" is invalid", *argv); } else if (strcmp(*argv, "replay-seq") == 0) { NEXT_ARG(); if (get_u32(&seq, *argv, 0)) invarg("value after \"replay-seq\" is invalid", *argv); } else if (strcmp(*argv, "replay-seq-hi") == 0) { NEXT_ARG(); if (get_u32(&seq_hi, *argv, 0)) invarg("value after \"replay-seq-hi\" is invalid", *argv); } else if (strcmp(*argv, "replay-oseq") == 0) { NEXT_ARG(); if (get_u32(&oseq, *argv, 0)) invarg("value after \"replay-oseq\" is invalid", *argv); } else if (strcmp(*argv, "replay-oseq-hi") == 0) { NEXT_ARG(); if (get_u32(&oseq_hi, *argv, 0)) invarg("value after \"replay-oseq-hi\" is invalid", *argv); } else if (strcmp(*argv, "flag") == 0) { NEXT_ARG(); xfrm_state_flag_parse(&req.xsinfo.flags, &argc, &argv); } else if (strcmp(*argv, "extra-flag") == 0) { NEXT_ARG(); xfrm_state_extra_flag_parse(&extra_flags, &argc, &argv); } else if (strcmp(*argv, "sel") == 0) { NEXT_ARG(); preferred_family = AF_UNSPEC; xfrm_selector_parse(&req.xsinfo.sel, &argc, &argv); preferred_family = req.xsinfo.sel.family; } else if (strcmp(*argv, "limit") == 0) { NEXT_ARG(); xfrm_lifetime_cfg_parse(&req.xsinfo.lft, &argc, &argv); } else if (strcmp(*argv, "encap") == 0) { struct xfrm_encap_tmpl encap; inet_prefix oa; NEXT_ARG(); xfrm_encap_type_parse(&encap.encap_type, &argc, &argv); NEXT_ARG(); if (get_u16(&encap.encap_sport, *argv, 0)) invarg("SPORT value after \"encap\" is invalid", *argv); encap.encap_sport = htons(encap.encap_sport); NEXT_ARG(); if (get_u16(&encap.encap_dport, *argv, 0)) invarg("DPORT value after \"encap\" is invalid", *argv); encap.encap_dport = htons(encap.encap_dport); NEXT_ARG(); get_addr(&oa, *argv, AF_UNSPEC); memcpy(&encap.encap_oa, &oa.data, sizeof(encap.encap_oa)); addattr_l(&req.n, sizeof(req.buf), XFRMA_ENCAP, (void *)&encap, sizeof(encap)); } else if (strcmp(*argv, "coa") == 0) { inet_prefix coa; xfrm_address_t xcoa; if (coap) duparg("coa", *argv); coap = *argv; NEXT_ARG(); get_prefix(&coa, *argv, preferred_family); if (coa.family == AF_UNSPEC) invarg("value after \"coa\" has an unrecognized address family", *argv); if (coa.bytelen > sizeof(xcoa)) invarg("value after \"coa\" is too large", *argv); memset(&xcoa, 0, sizeof(xcoa)); memcpy(&xcoa, &coa.data, coa.bytelen); addattr_l(&req.n, sizeof(req.buf), XFRMA_COADDR, (void *)&xcoa, sizeof(xcoa)); } else if (strcmp(*argv, "ctx") == 0) { char *context; if (sctxp) duparg("ctx", *argv); sctxp = *argv; NEXT_ARG(); context = *argv; xfrm_sctx_parse((char *)&ctx.str, context, &ctx.sctx); addattr_l(&req.n, sizeof(req.buf), XFRMA_SEC_CTX, (void *)&ctx, ctx.sctx.len); } else { /* try to assume ALGO */ int type = xfrm_algotype_getbyname(*argv); switch (type) { case XFRMA_ALG_AEAD: case XFRMA_ALG_CRYPT: case XFRMA_ALG_AUTH: case XFRMA_ALG_AUTH_TRUNC: case XFRMA_ALG_COMP: { /* ALGO */ struct { union { struct xfrm_algo alg; struct xfrm_algo_aead aead; struct xfrm_algo_auth auth; } u; char buf[XFRM_ALGO_KEY_BUF_SIZE]; } alg = {}; int len; __u32 icvlen, trunclen; char *name; char *key = ""; char *buf; switch (type) { case XFRMA_ALG_AEAD: if (ealgop || aalgop || aeadop) duparg("ALGO-TYPE", *argv); aeadop = *argv; break; case XFRMA_ALG_CRYPT: if (ealgop || aeadop) duparg("ALGO-TYPE", *argv); ealgop = *argv; break; case XFRMA_ALG_AUTH: case XFRMA_ALG_AUTH_TRUNC: if (aalgop || aeadop) duparg("ALGO-TYPE", *argv); aalgop = *argv; break; case XFRMA_ALG_COMP: if (calgop) duparg("ALGO-TYPE", *argv); calgop = *argv; break; default: /* not reached */ invarg("ALGO-TYPE value is invalid\n", *argv); } if (!NEXT_ARG_OK()) missarg("ALGO-NAME"); NEXT_ARG(); name = *argv; switch (type) { case XFRMA_ALG_AEAD: case XFRMA_ALG_CRYPT: case XFRMA_ALG_AUTH: case XFRMA_ALG_AUTH_TRUNC: if (!NEXT_ARG_OK()) missarg("ALGO-KEYMAT"); NEXT_ARG(); key = *argv; break; } buf = alg.u.alg.alg_key; len = sizeof(alg.u.alg); switch (type) { case XFRMA_ALG_AEAD: if (!NEXT_ARG_OK()) missarg("ALGO-ICV-LEN"); NEXT_ARG(); if (get_u32(&icvlen, *argv, 0)) invarg("ALGO-ICV-LEN value is invalid", *argv); alg.u.aead.alg_icv_len = icvlen; buf = alg.u.aead.alg_key; len = sizeof(alg.u.aead); break; case XFRMA_ALG_AUTH_TRUNC: if (!NEXT_ARG_OK()) missarg("ALGO-TRUNC-LEN"); NEXT_ARG(); if (get_u32(&trunclen, *argv, 0)) invarg("ALGO-TRUNC-LEN value is invalid", *argv); alg.u.auth.alg_trunc_len = trunclen; buf = alg.u.auth.alg_key; len = sizeof(alg.u.auth); break; } xfrm_algo_parse((void *)&alg, type, name, key, buf, sizeof(alg.buf)); len += alg.u.alg.alg_key_len; addattr_l(&req.n, sizeof(req.buf), type, (void *)&alg, len); break; } default: /* try to assume ID */ if (idp) invarg("unknown", *argv); idp = *argv; /* ID */ xfrm_id_parse(&req.xsinfo.saddr, &req.xsinfo.id, &req.xsinfo.family, 0, &argc, &argv); if (preferred_family == AF_UNSPEC) preferred_family = req.xsinfo.family; } } argc--; argv++; } if (req.xsinfo.flags & XFRM_STATE_ESN && replay_window == 0) { fprintf(stderr, "Error: esn flag set without replay-window.\n"); exit(-1); } if (replay_window > XFRMA_REPLAY_ESN_MAX) { fprintf(stderr, "Error: replay-window (%u) > XFRMA_REPLAY_ESN_MAX (%u).\n", replay_window, XFRMA_REPLAY_ESN_MAX); exit(-1); } if (req.xsinfo.flags & XFRM_STATE_ESN || replay_window > (sizeof(replay.bitmap) * 8)) { replay_esn.seq = seq; replay_esn.oseq = oseq; replay_esn.seq_hi = seq_hi; replay_esn.oseq_hi = oseq_hi; replay_esn.replay_window = replay_window; replay_esn.bmp_len = (replay_window + sizeof(__u32) * 8 - 1) / (sizeof(__u32) * 8); addattr_l(&req.n, sizeof(req.buf), XFRMA_REPLAY_ESN_VAL, &replay_esn, sizeof(replay_esn)); } else { if (seq || oseq) { replay.seq = seq; replay.oseq = oseq; addattr_l(&req.n, sizeof(req.buf), XFRMA_REPLAY_VAL, &replay, sizeof(replay)); } req.xsinfo.replay_window = replay_window; } if (extra_flags) addattr32(&req.n, sizeof(req.buf), XFRMA_SA_EXTRA_FLAGS, extra_flags); if (!idp) { fprintf(stderr, "Not enough information: ID is required\n"); exit(1); } if (mark.m) { int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK, (void *)&mark, sizeof(mark)); if (r < 0) { fprintf(stderr, "XFRMA_MARK failed\n"); exit(1); } } if (xfrm_xfrmproto_is_ipsec(req.xsinfo.id.proto)) { switch (req.xsinfo.mode) { case XFRM_MODE_TRANSPORT: case XFRM_MODE_TUNNEL: break; case XFRM_MODE_BEET: if (req.xsinfo.id.proto == IPPROTO_ESP) break; default: fprintf(stderr, "MODE value is invalid with XFRM-PROTO value \"%s\"\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } switch (req.xsinfo.id.proto) { case IPPROTO_ESP: if (calgop) { fprintf(stderr, "ALGO-TYPE value \"%s\" is invalid with XFRM-PROTO value \"%s\"\n", strxf_algotype(XFRMA_ALG_COMP), strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } if (!ealgop && !aeadop) { fprintf(stderr, "ALGO-TYPE value \"%s\" or \"%s\" is required with XFRM-PROTO value \"%s\"\n", strxf_algotype(XFRMA_ALG_CRYPT), strxf_algotype(XFRMA_ALG_AEAD), strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } break; case IPPROTO_AH: if (ealgop || aeadop || calgop) { fprintf(stderr, "ALGO-TYPE values \"%s\", \"%s\", and \"%s\" are invalid with XFRM-PROTO value \"%s\"\n", strxf_algotype(XFRMA_ALG_CRYPT), strxf_algotype(XFRMA_ALG_AEAD), strxf_algotype(XFRMA_ALG_COMP), strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } if (!aalgop) { fprintf(stderr, "ALGO-TYPE value \"%s\" or \"%s\" is required with XFRM-PROTO value \"%s\"\n", strxf_algotype(XFRMA_ALG_AUTH), strxf_algotype(XFRMA_ALG_AUTH_TRUNC), strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } break; case IPPROTO_COMP: if (ealgop || aalgop || aeadop) { fprintf(stderr, "ALGO-TYPE values \"%s\", \"%s\", \"%s\", and \"%s\" are invalid with XFRM-PROTO value \"%s\"\n", strxf_algotype(XFRMA_ALG_CRYPT), strxf_algotype(XFRMA_ALG_AUTH), strxf_algotype(XFRMA_ALG_AUTH_TRUNC), strxf_algotype(XFRMA_ALG_AEAD), strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } if (!calgop) { fprintf(stderr, "ALGO-TYPE value \"%s\" is required with XFRM-PROTO value \"%s\"\n", strxf_algotype(XFRMA_ALG_COMP), strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } break; } } else { if (ealgop || aalgop || aeadop || calgop) { fprintf(stderr, "ALGO is invalid with XFRM-PROTO value \"%s\"\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } } if (xfrm_xfrmproto_is_ro(req.xsinfo.id.proto)) { switch (req.xsinfo.mode) { case XFRM_MODE_ROUTEOPTIMIZATION: case XFRM_MODE_IN_TRIGGER: break; case 0: fprintf(stderr, "\"mode\" is required with XFRM-PROTO value \"%s\"\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); default: fprintf(stderr, "MODE value is invalid with XFRM-PROTO value \"%s\"\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } if (!coap) { fprintf(stderr, "\"coa\" is required with XFRM-PROTO value \"%s\"\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } } else { if (coap) { fprintf(stderr, "\"coa\" is invalid with XFRM-PROTO value \"%s\"\n", strxf_xfrmproto(req.xsinfo.id.proto)); exit(1); } } if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) exit(1); if (req.xsinfo.family == AF_UNSPEC) req.xsinfo.family = AF_INET; if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) exit(2); rtnl_close(&rth); return 0; }
static int ipntable_modify(int cmd, int flags, int argc, char **argv) { struct { struct nlmsghdr n; struct ndtmsg ndtm; char buf[1024]; } req = { .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndtmsg)), .n.nlmsg_flags = NLM_F_REQUEST | flags, .n.nlmsg_type = cmd, .ndtm.ndtm_family = preferred_family, }; char *namep = NULL; char *threshsp = NULL; char *gc_intp = NULL; char parms_buf[1024] = {}; struct rtattr *parms_rta = (struct rtattr *)parms_buf; int parms_change = 0; parms_rta->rta_type = NDTA_PARMS; parms_rta->rta_len = RTA_LENGTH(0); while (argc > 0) { if (strcmp(*argv, "name") == 0) { int len; NEXT_ARG(); if (namep) duparg("NAME", *argv); namep = *argv; len = strlen(namep) + 1; addattr_l(&req.n, sizeof(req), NDTA_NAME, namep, len); } else if (strcmp(*argv, "thresh1") == 0) { __u32 thresh1; NEXT_ARG(); threshsp = *argv; if (get_u32(&thresh1, *argv, 0)) invarg("\"thresh1\" value is invalid", *argv); addattr32(&req.n, sizeof(req), NDTA_THRESH1, thresh1); } else if (strcmp(*argv, "thresh2") == 0) { __u32 thresh2; NEXT_ARG(); threshsp = *argv; if (get_u32(&thresh2, *argv, 0)) invarg("\"thresh2\" value is invalid", *argv); addattr32(&req.n, sizeof(req), NDTA_THRESH2, thresh2); } else if (strcmp(*argv, "thresh3") == 0) { __u32 thresh3; NEXT_ARG(); threshsp = *argv; if (get_u32(&thresh3, *argv, 0)) invarg("\"thresh3\" value is invalid", *argv); addattr32(&req.n, sizeof(req), NDTA_THRESH3, thresh3); } else if (strcmp(*argv, "gc_int") == 0) { __u64 gc_int; NEXT_ARG(); gc_intp = *argv; if (get_u64(&gc_int, *argv, 0)) invarg("\"gc_int\" value is invalid", *argv); addattr_l(&req.n, sizeof(req), NDTA_GC_INTERVAL, &gc_int, sizeof(gc_int)); } else if (strcmp(*argv, "dev") == 0) { __u32 ifindex; NEXT_ARG(); ifindex = ll_name_to_index(*argv); if (!ifindex) return nodev(*argv); rta_addattr32(parms_rta, sizeof(parms_buf), NDTPA_IFINDEX, ifindex); } else if (strcmp(*argv, "base_reachable") == 0) { __u64 breachable; NEXT_ARG(); if (get_u64(&breachable, *argv, 0)) invarg("\"base_reachable\" value is invalid", *argv); rta_addattr_l(parms_rta, sizeof(parms_buf), NDTPA_BASE_REACHABLE_TIME, &breachable, sizeof(breachable)); parms_change = 1; } else if (strcmp(*argv, "retrans") == 0) { __u64 retrans; NEXT_ARG(); if (get_u64(&retrans, *argv, 0)) invarg("\"retrans\" value is invalid", *argv); rta_addattr_l(parms_rta, sizeof(parms_buf), NDTPA_RETRANS_TIME, &retrans, sizeof(retrans)); parms_change = 1; } else if (strcmp(*argv, "gc_stale") == 0) { __u64 gc_stale; NEXT_ARG(); if (get_u64(&gc_stale, *argv, 0)) invarg("\"gc_stale\" value is invalid", *argv); rta_addattr_l(parms_rta, sizeof(parms_buf), NDTPA_GC_STALETIME, &gc_stale, sizeof(gc_stale)); parms_change = 1; } else if (strcmp(*argv, "delay_probe") == 0) { __u64 delay_probe; NEXT_ARG(); if (get_u64(&delay_probe, *argv, 0)) invarg("\"delay_probe\" value is invalid", *argv); rta_addattr_l(parms_rta, sizeof(parms_buf), NDTPA_DELAY_PROBE_TIME, &delay_probe, sizeof(delay_probe)); parms_change = 1; } else if (strcmp(*argv, "queue") == 0) { __u32 queue; NEXT_ARG(); if (get_u32(&queue, *argv, 0)) invarg("\"queue\" value is invalid", *argv); rta_addattr32(parms_rta, sizeof(parms_buf), NDTPA_QUEUE_LEN, queue); parms_change = 1; } else if (strcmp(*argv, "app_probes") == 0) { __u32 aprobe; NEXT_ARG(); if (get_u32(&aprobe, *argv, 0)) invarg("\"app_probes\" value is invalid", *argv); rta_addattr32(parms_rta, sizeof(parms_buf), NDTPA_APP_PROBES, aprobe); parms_change = 1; } else if (strcmp(*argv, "ucast_probes") == 0) { __u32 uprobe; NEXT_ARG(); if (get_u32(&uprobe, *argv, 0)) invarg("\"ucast_probes\" value is invalid", *argv); rta_addattr32(parms_rta, sizeof(parms_buf), NDTPA_UCAST_PROBES, uprobe); parms_change = 1; } else if (strcmp(*argv, "mcast_probes") == 0) { __u32 mprobe; NEXT_ARG(); if (get_u32(&mprobe, *argv, 0)) invarg("\"mcast_probes\" value is invalid", *argv); rta_addattr32(parms_rta, sizeof(parms_buf), NDTPA_MCAST_PROBES, mprobe); parms_change = 1; } else if (strcmp(*argv, "anycast_delay") == 0) { __u64 anycast_delay; NEXT_ARG(); if (get_u64(&anycast_delay, *argv, 0)) invarg("\"anycast_delay\" value is invalid", *argv); rta_addattr_l(parms_rta, sizeof(parms_buf), NDTPA_ANYCAST_DELAY, &anycast_delay, sizeof(anycast_delay)); parms_change = 1; } else if (strcmp(*argv, "proxy_delay") == 0) { __u64 proxy_delay; NEXT_ARG(); if (get_u64(&proxy_delay, *argv, 0)) invarg("\"proxy_delay\" value is invalid", *argv); rta_addattr_l(parms_rta, sizeof(parms_buf), NDTPA_PROXY_DELAY, &proxy_delay, sizeof(proxy_delay)); parms_change = 1; } else if (strcmp(*argv, "proxy_queue") == 0) { __u32 pqueue; NEXT_ARG(); if (get_u32(&pqueue, *argv, 0)) invarg("\"proxy_queue\" value is invalid", *argv); rta_addattr32(parms_rta, sizeof(parms_buf), NDTPA_PROXY_QLEN, pqueue); parms_change = 1; } else if (strcmp(*argv, "locktime") == 0) { __u64 locktime; NEXT_ARG(); if (get_u64(&locktime, *argv, 0)) invarg("\"locktime\" value is invalid", *argv); rta_addattr_l(parms_rta, sizeof(parms_buf), NDTPA_LOCKTIME, &locktime, sizeof(locktime)); parms_change = 1; } else { invarg("unknown", *argv); } argc--; argv++; } if (!namep) missarg("NAME"); if (!threshsp && !gc_intp && !parms_change) { fprintf(stderr, "Not enough information: changeable attributes required.\n"); exit(-1); } if (parms_rta->rta_len > RTA_LENGTH(0)) { addattr_l(&req.n, sizeof(req), NDTA_PARMS, RTA_DATA(parms_rta), RTA_PAYLOAD(parms_rta)); } if (rtnl_talk(&rth, &req.n, NULL) < 0) exit(2); return 0; } static const char *ntable_strtime_delta(__u32 msec) { static char str[32]; struct timeval now = {}; time_t t; struct tm *tp; if (msec == 0) goto error; if (gettimeofday(&now, NULL) < 0) { perror("gettimeofday"); goto error; } t = now.tv_sec - (msec / 1000); tp = localtime(&t); if (!tp) goto error; strftime(str, sizeof(str), "%Y-%m-%d %T", tp); return str; error: strcpy(str, "(error)"); return str; } static void print_ndtconfig(const struct ndt_config *ndtc) { print_uint(PRINT_ANY, "key_length", " config key_len %u ", ndtc->ndtc_key_len); print_uint(PRINT_ANY, "entry_size", "entry_size %u ", ndtc->ndtc_entry_size); print_uint(PRINT_ANY, "entries", "entries %u ", ndtc->ndtc_entries); print_nl(); print_string(PRINT_ANY, "last_flush", " last_flush %s ", ntable_strtime_delta(ndtc->ndtc_last_flush)); print_string(PRINT_ANY, "last_rand", "last_rand %s ", ntable_strtime_delta(ndtc->ndtc_last_rand)); print_nl(); print_uint(PRINT_ANY, "hash_rnd", " hash_rnd %u ", ndtc->ndtc_hash_rnd); print_0xhex(PRINT_ANY, "hash_mask", "hash_mask %08llx ", ndtc->ndtc_hash_mask); print_uint(PRINT_ANY, "hash_chain_gc", "hash_chain_gc %u ", ndtc->ndtc_hash_chain_gc); print_uint(PRINT_ANY, "proxy_qlen", "proxy_qlen %u ", ndtc->ndtc_proxy_qlen); print_nl(); }