static int restore_handler(const struct sockaddr_nl *nl, struct nlmsghdr *n, void *arg) { int ret; n->nlmsg_flags |= NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK; ll_init_map(&rth); ret = rtnl_talk(&rth, n, n, sizeof(*n)); if ((ret < 0) && (errno == EEXIST)) ret = 0; return ret; }
int mpls_tunnel_add(int cmd, unsigned flags, int argc, char **argv) { //__u32 labelspace = -2; struct genlmsghdr *ghdr; struct { struct nlmsghdr n; char buf[4096]; } req; struct mpls_tunnel_req ls; memset(&req, 0, sizeof(req)); memset(&ls, 0, sizeof(ls)); req.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); req.n.nlmsg_flags = NLM_F_REQUEST|flags; req.n.nlmsg_type = PF_MPLS; ghdr = NLMSG_DATA(&req.n); ghdr->cmd = cmd; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); //ls.mls_ifindex = ll_name_to_index(*argv); strncpy(ls.mt_ifname, *argv, IFNAMSIZ); } /*else if (strcmp(*argv, "labelspace") == 0) { NEXT_ARG(); if (get_unsigned(&labelspace, *argv, 0)) invarg(*argv, "invalid labelspace"); ls.mls_labelspace = labelspace; } */else { usage(); } argc--; argv++; } /* if (ls.mls_ifindex == 0 || ls.mls_labelspace == -2) { fprintf(stderr, "Invalid arguments\n"); exit(1); }*/ addattr_l(&req.n, sizeof(req), MPLS_ATTR_TUNNEL, &ls, sizeof(ls)); if (rtnl_talk(&rth2, &req.n, 0, 0, NULL, NULL, NULL) < 0) return 2; //exit(2); return 0; }
int ipoe_nl_modify(int ifindex, uint32_t peer_addr, uint32_t addr, const char *ifname, uint8_t *hwaddr) { struct rtnl_handle rth; struct nlmsghdr *nlh; struct genlmsghdr *ghdr; int ret = 0; struct { struct nlmsghdr n; char buf[1024]; } req; union { uint8_t hwaddr[6]; uint64_t u64; } u; if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC)) { log_ppp_error("ipoe: cannot open generic netlink socket\n"); return -1; } nlh = &req.n; nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; nlh->nlmsg_type = ipoe_genl_id; ghdr = NLMSG_DATA(&req.n); ghdr->cmd = IPOE_CMD_MODIFY; addattr32(nlh, 1024, IPOE_ATTR_IFINDEX, ifindex); addattr32(nlh, 1024, IPOE_ATTR_PEER_ADDR, peer_addr); addattr32(nlh, 1024, IPOE_ATTR_ADDR, addr); if (hwaddr) { memcpy(u.hwaddr, hwaddr, 6); addattr_l(nlh, 1024, IPOE_ATTR_HWADDR, &u.u64, 8); } if (ifname) addattr_l(nlh, 1024, IPOE_ATTR_IFNAME, ifname, strlen(ifname) + 1); if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) { log_ppp_error("ipoe: nl_create: error talking to kernel\n"); ret = -1; } rtnl_close(&rth); return ret; }
static int xfrm_policy_flush(int argc, char **argv) { struct rtnl_handle rth; struct { struct nlmsghdr n; char buf[RTA_BUF_SIZE]; } req; char *ptypep = NULL; struct xfrm_userpolicy_type upt; memset(&req, 0, sizeof(req)); memset(&upt, 0, sizeof(upt)); req.n.nlmsg_len = NLMSG_LENGTH(0); /* nlmsg data is nothing */ req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = XFRM_MSG_FLUSHPOLICY; while (argc > 0) { if (strcmp(*argv, "ptype") == 0) { if (ptypep) duparg("ptype", *argv); ptypep = *argv; NEXT_ARG(); xfrm_policy_ptype_parse(&upt.type, &argc, &argv); } else invarg("unknown", *argv); argc--; argv++; } if (ptypep) { addattr_l(&req.n, sizeof(req), XFRMA_POLICY_TYPE, (void *)&upt, sizeof(upt)); } if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) exit(1); if (show_stats > 1) fprintf(stderr, "Flush policy\n"); if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) exit(2); rtnl_close(&rth); return 0; }
static int get_netnsid_from_name(const char *name) { struct { struct nlmsghdr n; struct rtgenmsg g; char buf[1024]; } req, answer; struct rtattr *tb[NETNSA_MAX + 1]; struct rtgenmsg *rthdr; int len, fd; 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 = netns_get_fd(name); if (fd < 0) return fd; addattr32(&req.n, 1024, NETNSA_FD, fd); if (rtnl_talk(&rth, &req.n, 0, 0, &answer.n) < 0) { close(fd); return -2; } close(fd); /* Validate message and parse attributes */ if (answer.n.nlmsg_type == NLMSG_ERROR) return -1; rthdr = NLMSG_DATA(&answer.n); len = answer.n.nlmsg_len - NLMSG_SPACE(sizeof(*rthdr)); if (len < 0) return -1; parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len); if (tb[NETNSA_NSID]) return rta_getattr_u32(tb[NETNSA_NSID]); return -1; }
static int create_session(struct l2tp_parm *p) { GENL_REQUEST(req, 1024, genl_family, 0, L2TP_GENL_VERSION, L2TP_CMD_SESSION_CREATE, NLM_F_REQUEST | NLM_F_ACK); addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->tunnel_id); addattr32(&req.n, 1024, L2TP_ATTR_PEER_CONN_ID, p->peer_tunnel_id); addattr32(&req.n, 1024, L2TP_ATTR_SESSION_ID, p->session_id); addattr32(&req.n, 1024, L2TP_ATTR_PEER_SESSION_ID, p->peer_session_id); addattr16(&req.n, 1024, L2TP_ATTR_PW_TYPE, p->pw_type); addattr8(&req.n, 1024, L2TP_ATTR_L2SPEC_TYPE, p->l2spec_type); addattr8(&req.n, 1024, L2TP_ATTR_L2SPEC_LEN, p->l2spec_len); if (p->mtu) addattr16(&req.n, 1024, L2TP_ATTR_MTU, p->mtu); if (p->recv_seq) addattr8(&req.n, 1024, L2TP_ATTR_RECV_SEQ, 1); if (p->send_seq) addattr8(&req.n, 1024, L2TP_ATTR_SEND_SEQ, 1); if (p->lns_mode) addattr(&req.n, 1024, L2TP_ATTR_LNS_MODE); if (p->data_seq) addattr8(&req.n, 1024, L2TP_ATTR_DATA_SEQ, p->data_seq); if (p->reorder_timeout) addattr64(&req.n, 1024, L2TP_ATTR_RECV_TIMEOUT, p->reorder_timeout); if (p->offset) addattr16(&req.n, 1024, L2TP_ATTR_OFFSET, p->offset); if (p->cookie_len) addattr_l(&req.n, 1024, L2TP_ATTR_COOKIE, p->cookie, p->cookie_len); if (p->peer_cookie_len) addattr_l(&req.n, 1024, L2TP_ATTR_PEER_COOKIE, p->peer_cookie, p->peer_cookie_len); if (p->ifname) addattrstrz(&req.n, 1024, L2TP_ATTR_IFNAME, p->ifname); if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0) return -2; return 0; }
int genl_resolve_family(struct rtnl_handle *grth, const char *family) { GENL_REQUEST(req, 1024, GENL_ID_CTRL, 0, 0, CTRL_CMD_GETFAMILY, NLM_F_REQUEST); struct nlmsghdr *answer; int fnum; addattr_l(&req.n, sizeof(req), CTRL_ATTR_FAMILY_NAME, family, strlen(family) + 1); if (rtnl_talk(grth, &req.n, &answer) < 0) { fprintf(stderr, "Error talking to the kernel\n"); return -2; } fnum = genl_parse_getfamily(answer); free(answer); return fnum; }
int ipaddr_op( int ifindex, uint32_t addr, uint8_t length, int addF ) { struct rtnl_handle rth; struct { struct nlmsghdr n; struct ifaddrmsg ifa; char buf[256]; } req; uint32_t bcast; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = addF ? RTM_NEWADDR : RTM_DELADDR; req.ifa.ifa_family = AF_INET; req.ifa.ifa_index = ifindex; req.ifa.ifa_prefixlen = 32; req.ifa.ifa_prefixlen = length; addr = htonl( addr ); addattr_l(&req.n, sizeof(req), IFA_LOCAL, &addr, sizeof(addr) ); bcast = addr | htonl((1 << (32 - length)) - 1); addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &bcast, sizeof(bcast) ); if (rtnl_open(&rth, 0) < 0){ rtnl_close( &rth ); return -1; } if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) { rtnl_close( &rth ); return -1; } /* to close the clocket */ rtnl_close( &rth ); return(0); }
void TunManager::addRemoveTable(int ifIdx, RouterID rid, bool add) { // We just store default routes (one for IPv4 and one for IPv6) in each route // table. struct { struct nlmsghdr n; struct rtmsg r; char buf[256]; } req; const folly::IPAddress addrs[] = { IPAddress{"0.0.0.0"}, // v4 default IPAddress{"::0"}, // v6 default }; for (const auto& addr : addrs) { memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; if (add) { req.n.nlmsg_type = RTM_NEWROUTE; req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_REPLACE; } else { req.n.nlmsg_type = RTM_DELROUTE; } req.r.rtm_family = addr.family(); req.r.rtm_table = getTableId(rid); req.r.rtm_scope = RT_SCOPE_NOWHERE; req.r.rtm_protocol = RTPROT_FBOSS; req.r.rtm_scope = RT_SCOPE_UNIVERSE; req.r.rtm_type = RTN_UNICAST; req.r.rtm_dst_len = 0; // default route, /0 addattr_l(&req.n, sizeof(req), RTA_DST, addr.bytes(), addr.byteCount()); addattr32(&req.n, sizeof(req), RTA_OIF, ifIdx); auto ret = rtnl_talk(&rth_, &req.n, 0, 0, nullptr); sysCheckError(ret, "Failed to ", add ? "add" : "remove", " default route ", addr, " @ index ", ifIdx, " in table ", getTableId(rid), " for router ", rid); LOG(INFO) << (add ? "Added" : "Removed") << " default route " << addr << " @ index " << ifIdx << " in table " << getTableId(rid) << " for router " << rid; } }
void TunManager::bringupIntf(const std::string& name, int ifIndex) { // TODO: We need to change the interface status based on real HW // interface status (up/down). Make them up all the time for now. struct { struct nlmsghdr n; struct ifinfomsg ifi; char buf[256]; } req; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); req.n.nlmsg_type = RTM_NEWLINK; req.n.nlmsg_flags = NLM_F_REQUEST; req.ifi.ifi_family = AF_UNSPEC; req.ifi.ifi_change |= IFF_UP; req.ifi.ifi_flags |= IFF_UP; req.ifi.ifi_index = ifIndex; auto ret = rtnl_talk(&rth_, &req.n, 0, 0, nullptr); sysCheckError(ret, "Failed to bring up interface ", name, " @ index ", ifIndex); LOG(INFO) << "Brought up interface " << name << " @ index " << ifIndex; }
static PyObject* pyrtnl_talk(PyObject* obj, PyObject* args) { PyRtnlObject* self = (PyRtnlObject*)obj; char* msg; int len; int peer = 0; int groups = 0; if (!PyArg_ParseTuple(args, "s#|ii", &msg, &len, &peer, &groups)) return NULL; if (rtnl_talk(&self->rth, (struct nlmsghdr*)msg, peer, groups, NULL, NULL, NULL) < 0) { PyErr_SetString(PyExc_IOError, "error sending message"); return NULL; } Py_INCREF(Py_None); return Py_None; }
static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr * tb[RTA_MAX+1]; len -= NLMSG_LENGTH(sizeof(*r)); if (len < 0) return -1; parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); if (tb[RTA_PRIORITY]) { n->nlmsg_type = RTM_DELRULE; n->nlmsg_flags = NLM_F_REQUEST; if (rtnl_talk(&rth, n, 0, 0, NULL, NULL, NULL) < 0) return -2; } return 0; }
static int create_tunnel(struct l2tp_parm *p) { uint32_t local_attr = L2TP_ATTR_IP_SADDR; uint32_t peer_attr = L2TP_ATTR_IP_DADDR; GENL_REQUEST(req, 1024, genl_family, 0, L2TP_GENL_VERSION, L2TP_CMD_TUNNEL_CREATE, NLM_F_REQUEST | NLM_F_ACK); addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->tunnel_id); addattr32(&req.n, 1024, L2TP_ATTR_PEER_CONN_ID, p->peer_tunnel_id); addattr8(&req.n, 1024, L2TP_ATTR_PROTO_VERSION, 3); addattr16(&req.n, 1024, L2TP_ATTR_ENCAP_TYPE, p->encap); if (p->local_ip.family == AF_INET6) local_attr = L2TP_ATTR_IP6_SADDR; addattr_l(&req.n, 1024, local_attr, &p->local_ip.data, p->local_ip.bytelen); if (p->peer_ip.family == AF_INET6) peer_attr = L2TP_ATTR_IP6_DADDR; addattr_l(&req.n, 1024, peer_attr, &p->peer_ip.data, p->peer_ip.bytelen); if (p->encap == L2TP_ENCAPTYPE_UDP) { addattr16(&req.n, 1024, L2TP_ATTR_UDP_SPORT, p->local_udp_port); addattr16(&req.n, 1024, L2TP_ATTR_UDP_DPORT, p->peer_udp_port); if (p->udp_csum) addattr8(&req.n, 1024, L2TP_ATTR_UDP_CSUM, 1); if (!p->udp6_csum_tx) addattr(&req.n, 1024, L2TP_ATTR_UDP_ZERO_CSUM6_TX); if (!p->udp6_csum_rx) addattr(&req.n, 1024, L2TP_ATTR_UDP_ZERO_CSUM6_RX); } if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0) return -2; return 0; }
int tc_action_modify(int cmd, unsigned flags, int *argc_p, char ***argv_p) { int argc = *argc_p; char **argv = *argv_p; int ret = 0; struct rtattr *tail; struct { struct nlmsghdr n; struct tcamsg t; char buf[MAX_MSG]; } req; req.t.tca_family = AF_UNSPEC; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcamsg)); req.n.nlmsg_flags = NLM_F_REQUEST|flags; req.n.nlmsg_type = cmd; tail = NLMSG_TAIL(&req.n); argc -=1; argv +=1; if (parse_action(&argc, &argv, TCA_ACT_TAB, &req.n)) { fprintf(stderr, "Illegal \"action\"\n"); return -1; } tail->rta_len = (void *) NLMSG_TAIL(&req.n) - (void *) tail; if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) { fprintf(stderr, "We have an error talking to the kernel\n"); ret = -1; } *argc_p = argc; *argv_p = argv; return ret; }
static int modify_neigh(struct xia_xid *dst, unsigned char *lladdr, int lladdr_len, unsigned oif, int to_add) { struct { struct nlmsghdr n; struct rtmsg r; char buf[1024]; } req; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); if (to_add) { /* XXX Does one really needs all these flags? */ req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; req.n.nlmsg_type = RTM_NEWROUTE; req.r.rtm_scope = RT_SCOPE_LINK; } else { req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_DELROUTE; req.r.rtm_scope = RT_SCOPE_NOWHERE; } req.r.rtm_family = AF_XIA; req.r.rtm_table = XRTABLE_MAIN_INDEX; req.r.rtm_protocol = RTPROT_BOOT; req.r.rtm_type = RTN_UNICAST; req.r.rtm_dst_len = sizeof(*dst); addattr_l(&req.n, sizeof(req), RTA_DST, dst, sizeof(*dst)); addattr_l(&req.n, sizeof(req), RTA_LLADDR, lladdr, lladdr_len); addattr32(&req.n, sizeof(req), RTA_OIF, oif); if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) exit(2); return 0; }
int ipoe_nl_add_vlan_mon_vid(int ifindex, int vid) { struct rtnl_handle rth; struct nlmsghdr *nlh; struct genlmsghdr *ghdr; struct { struct nlmsghdr n; char buf[1024]; } req; int r = 0; if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC)) { log_error("ipoe: cannot open generic netlink socket\n"); return -1; } nlh = &req.n; nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; nlh->nlmsg_type = ipoe_genl_id; ghdr = NLMSG_DATA(&req.n); ghdr->cmd = IPOE_CMD_ADD_VLAN_MON_VID; addattr32(nlh, 1024, IPOE_ATTR_IFINDEX, ifindex); addattr32(nlh, 1024, IPOE_ATTR_ADDR, vid); if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) { log_error("ipoe: nl_add_vlan_mon_vid: error talking to kernel\n"); r = -1; } rtnl_close(&rth); return r; }
void TunManager::addRemoveTunAddress( const std::string& name, uint32_t ifIndex, folly::IPAddress addr, uint8_t mask, bool add) { struct { struct nlmsghdr n; struct ifaddrmsg ifa; char buf[256]; } req; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); if (add) { req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; req.n.nlmsg_type = RTM_NEWADDR; } else { req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_DELADDR; } if (addr.isV4()) { req.ifa.ifa_family = AF_INET; addattr_l(&req.n, sizeof(req), IFA_LOCAL, addr.asV4().bytes(), folly::IPAddressV4::byteCount()); } else { req.ifa.ifa_family = AF_INET6; addattr_l(&req.n, sizeof(req), IFA_LOCAL, addr.asV6().bytes(), folly::IPAddressV6::byteCount()); } req.ifa.ifa_prefixlen = mask; req.ifa.ifa_index = ifIndex; auto ret = rtnl_talk(&rth_, &req.n, 0, 0, nullptr); sysCheckError(ret, "Failed to ", add ? "add" : "remove", " address ", addr, "/", static_cast<int>(mask), " to interface ", name, " @ index ", ifIndex); LOG(INFO) << (add ? "Added" : "Removed") << " address " << addr.str() << "/" << static_cast<int>(mask) << " on interface " << name << " @ index " << ifIndex; }
int ipoe_nl_add_exclude(uint32_t addr, int mask) { struct rtnl_handle rth; struct nlmsghdr *nlh; struct genlmsghdr *ghdr; struct { struct nlmsghdr n; char buf[1024]; } req; int ret = 0; if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC)) { log_ppp_error("ipoe: cannot open generic netlink socket\n"); return -1; } nlh = &req.n; nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; nlh->nlmsg_type = ipoe_genl_id; ghdr = NLMSG_DATA(&req.n); ghdr->cmd = IPOE_CMD_ADD_EXCLUDE; addattr32(nlh, 1024, IPOE_ATTR_ADDR, addr); if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) { log_ppp_error("ipoe: nl_add_net: error talking to kernel\n"); ret = -1; } rtnl_close(&rth); return ret; }
static int fdb_modify(int cmd, int flags, int argc, char **argv) { struct { struct nlmsghdr n; struct ndmsg ndm; char buf[256]; } req; char *addr = NULL; char *d = NULL; char abuf[ETH_ALEN]; int dst_ok = 0; inet_prefix dst; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); req.n.nlmsg_flags = NLM_F_REQUEST|flags; req.n.nlmsg_type = cmd; req.ndm.ndm_family = PF_BRIDGE; req.ndm.ndm_state = NUD_NOARP; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); d = *argv; } else if (strcmp(*argv, "dst") == 0) { NEXT_ARG(); if (dst_ok) duparg2("dst", *argv); get_addr(&dst, *argv, preferred_family); dst_ok = 1; } else if (strcmp(*argv, "self") == 0) { req.ndm.ndm_flags |= NTF_SELF; } else if (matches(*argv, "master") == 0) { req.ndm.ndm_flags |= NTF_MASTER; } else if (matches(*argv, "local") == 0|| matches(*argv, "permanent") == 0) { req.ndm.ndm_state |= NUD_PERMANENT; } else if (matches(*argv, "temp") == 0) { req.ndm.ndm_state |= NUD_REACHABLE; } else { if (strcmp(*argv, "to") == 0) { NEXT_ARG(); } if (matches(*argv, "help") == 0) usage(); if (addr) duparg2("to", *argv); addr = *argv; } argc--; argv++; } if (d == NULL || addr == NULL) { fprintf(stderr, "Device and address are required arguments.\n"); exit(-1); } /* Assume self */ if (!(req.ndm.ndm_flags&(NTF_SELF|NTF_MASTER))) req.ndm.ndm_flags |= NTF_SELF; /* Assume permanent */ if (!(req.ndm.ndm_state&(NUD_PERMANENT|NUD_REACHABLE))) req.ndm.ndm_state |= NUD_PERMANENT; if (sscanf(addr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", abuf, abuf+1, abuf+2, abuf+3, abuf+4, abuf+5) != 6) { fprintf(stderr, "Invalid mac address %s\n", addr); exit(-1); } addattr_l(&req.n, sizeof(req), NDA_LLADDR, abuf, ETH_ALEN); if (dst_ok) addattr_l(&req.n, sizeof(req), NDA_DST, &dst.data, dst.bytelen); req.ndm.ndm_ifindex = ll_name_to_index(d); if (req.ndm.ndm_ifindex == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", d); return -1; } if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) exit(2); return 0; }
static int xfrm_policy_modify(int cmd, unsigned flags, int argc, char **argv) { struct rtnl_handle rth; struct { struct nlmsghdr n; struct xfrm_userpolicy_info xpinfo; char buf[RTA_BUF_SIZE]; } req; char *dirp = NULL; char *selp = NULL; char *ptypep = NULL; struct xfrm_userpolicy_type upt; char tmpls_buf[XFRM_TMPLS_BUF_SIZE]; int tmpls_len = 0; memset(&req, 0, sizeof(req)); memset(&upt, 0, sizeof(upt)); memset(&tmpls_buf, 0, sizeof(tmpls_buf)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xpinfo)); req.n.nlmsg_flags = NLM_F_REQUEST|flags; req.n.nlmsg_type = cmd; req.xpinfo.sel.family = preferred_family; req.xpinfo.lft.soft_byte_limit = XFRM_INF; req.xpinfo.lft.hard_byte_limit = XFRM_INF; req.xpinfo.lft.soft_packet_limit = XFRM_INF; req.xpinfo.lft.hard_packet_limit = XFRM_INF; while (argc > 0) { if (strcmp(*argv, "dir") == 0) { if (dirp) duparg("dir", *argv); dirp = *argv; NEXT_ARG(); xfrm_policy_dir_parse(&req.xpinfo.dir, &argc, &argv); } else if (strcmp(*argv, "index") == 0) { NEXT_ARG(); if (get_u32(&req.xpinfo.index, *argv, 0)) invarg("\"INDEX\" is invalid", *argv); } else if (strcmp(*argv, "ptype") == 0) { if (ptypep) duparg("ptype", *argv); ptypep = *argv; NEXT_ARG(); xfrm_policy_ptype_parse(&upt.type, &argc, &argv); } else if (strcmp(*argv, "action") == 0) { NEXT_ARG(); if (strcmp(*argv, "allow") == 0) req.xpinfo.action = XFRM_POLICY_ALLOW; else if (strcmp(*argv, "block") == 0) req.xpinfo.action = XFRM_POLICY_BLOCK; else invarg("\"action\" value is invalid\n", *argv); } else if (strcmp(*argv, "priority") == 0) { NEXT_ARG(); if (get_u32(&req.xpinfo.priority, *argv, 0)) invarg("\"PRIORITY\" is invalid", *argv); } else if (strcmp(*argv, "flag") == 0) { NEXT_ARG(); xfrm_policy_flag_parse(&req.xpinfo.flags, &argc, &argv); } else if (strcmp(*argv, "limit") == 0) { NEXT_ARG(); xfrm_lifetime_cfg_parse(&req.xpinfo.lft, &argc, &argv); } else if (strcmp(*argv, "tmpl") == 0) { struct xfrm_user_tmpl *tmpl; if (tmpls_len + sizeof(*tmpl) > sizeof(tmpls_buf)) { fprintf(stderr, "Too many tmpls: buffer overflow\n"); exit(1); } tmpl = (struct xfrm_user_tmpl *)((char *)tmpls_buf + tmpls_len); tmpl->family = preferred_family; tmpl->aalgos = (~(__u32)0); tmpl->ealgos = (~(__u32)0); tmpl->calgos = (~(__u32)0); NEXT_ARG(); xfrm_tmpl_parse(tmpl, &argc, &argv); tmpls_len += sizeof(*tmpl); } else { if (selp) duparg("unknown", *argv); selp = *argv; xfrm_selector_parse(&req.xpinfo.sel, &argc, &argv); if (preferred_family == AF_UNSPEC) preferred_family = req.xpinfo.sel.family; } argc--; argv++; } if (!dirp) { fprintf(stderr, "Not enough information: \"DIR\" is required.\n"); exit(1); } if (ptypep) { addattr_l(&req.n, sizeof(req), XFRMA_POLICY_TYPE, (void *)&upt, sizeof(upt)); } if (tmpls_len > 0) { addattr_l(&req.n, sizeof(req), XFRMA_TMPL, (void *)tmpls_buf, tmpls_len); } if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) exit(1); if (req.xpinfo.sel.family == AF_UNSPEC) req.xpinfo.sel.family = AF_INET; if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) exit(2); rtnl_close(&rth); return 0; }
bool set_ip4(int iface_index, uint32_t address, uint8_t network) { bool is_success = false; int ret; struct { struct nlmsghdr nh; struct ifaddrmsg ip; char buf[256]; } req; struct rtnl_handle rth = { .fd = -1 }; uint32_t *ip_data; ret = rtnl_open(&rth, 0); if(ret < 0) { trace(LOG_ERR, "failed to open RTNL socket (code %d)", ret); goto error; } ip_data = calloc(8, sizeof(uint32_t)); if(ip_data == NULL) { trace(LOG_ERR, "failed to allocate memory for setting IPv4 address"); goto close_rtnl; } ip_data[0] = address; /* initialize netlink request */ memset(&req, 0, sizeof(req)); req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; req.nh.nlmsg_type = RTM_NEWADDR; /* ifaddrmsg info */ req.ip.ifa_family = AF_INET; /* IPv4 */ req.ip.ifa_prefixlen = network; req.ip.ifa_index = iface_index; addattr_l(&req.nh, sizeof(req), IFA_LOCAL, ip_data, 4); addattr_l(&req.nh, sizeof(req), IFA_ADDRESS, ip_data, 4); /* GOGOGO */ #if RTNL_TALK_PARAMS == 5 ret = rtnl_talk(&rth, &req.nh, 0, 0, NULL); #elif RTNL_TALK_PARAMS == 7 ret = rtnl_talk(&rth, &req.nh, 0, 0, NULL, NULL, NULL); #else # error "unsupported version of rtnl_talk()" #endif if(ret < 0) { trace(LOG_ERR, "failed to set IPv4 address %u.%u.%u.%u/%u (code %d)", (ntohl(address) >> 24) & 0xff, (ntohl(address) >> 16) & 0xff, (ntohl(address) >> 8) & 0xff, (ntohl(address) >> 0) & 0xff, network, ret); goto free_ip_data; } is_success = true; free_ip_data: free(ip_data); close_rtnl: rtnl_close(&rth); error: return is_success; }
int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv) { struct qdisc_util *q = NULL; struct tc_estimator est; char d[16]; char k[16]; struct { struct nlmsghdr n; struct tcmsg t; char buf[TCA_BUF_MAX]; } req; memset(&req, 0, sizeof(req)); memset(&est, 0, sizeof(est)); memset(&d, 0, sizeof(d)); memset(&k, 0, sizeof(k)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); req.n.nlmsg_flags = NLM_F_REQUEST|flags; req.n.nlmsg_type = cmd; req.t.tcm_family = AF_UNSPEC; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); if (d[0]) duparg("dev", *argv); strncpy(d, *argv, sizeof(d)-1); } else if (strcmp(*argv, "handle") == 0) { __u32 handle; if (req.t.tcm_handle) duparg("handle", *argv); NEXT_ARG(); if (get_qdisc_handle(&handle, *argv)) invarg(*argv, "invalid qdisc ID"); req.t.tcm_handle = handle; } else if (strcmp(*argv, "root") == 0) { if (req.t.tcm_parent) { fprintf(stderr, "Error: \"root\" is duplicate parent ID\n"); return -1; } req.t.tcm_parent = TC_H_ROOT; #ifdef TC_H_INGRESS } else if (strcmp(*argv, "ingress") == 0) { if (req.t.tcm_parent) { fprintf(stderr, "Error: \"ingress\" is a duplicate parent ID\n"); return -1; } req.t.tcm_parent = TC_H_INGRESS; strncpy(k, "ingress", sizeof(k)-1); q = get_qdisc_kind(k); req.t.tcm_handle = 0xffff0000; argc--; argv++; break; #endif } else if (strcmp(*argv, "parent") == 0) { __u32 handle; NEXT_ARG(); if (req.t.tcm_parent) duparg("parent", *argv); if (get_tc_classid(&handle, *argv)) invarg(*argv, "invalid parent ID"); req.t.tcm_parent = handle; } else if (matches(*argv, "estimator") == 0) { if (parse_estimator(&argc, &argv, &est)) return -1; } else if (matches(*argv, "help") == 0) { usage(); } else { strncpy(k, *argv, sizeof(k)-1); q = get_qdisc_kind(k); argc--; argv++; break; } argc--; argv++; } if (k[0]) addattr_l(&req.n, sizeof(req), TCA_KIND, k, strlen(k)+1); if (est.ewma_log) addattr_l(&req.n, sizeof(req), TCA_RATE, &est, sizeof(est)); if (q) { if (!q->parse_qopt) { fprintf(stderr, "qdisc '%s' does not support option parsing\n", k); return -1; } if (q->parse_qopt(q, argc, argv, &req.n)) return 1; } else { if (argc) { if (matches(*argv, "help") == 0) usage(); fprintf(stderr, "Garbage instead of arguments \"%s ...\". Try \"tc qdisc help\".\n", *argv); return -1; } } if (d[0]) { int idx; ll_init_map(&rth); if ((idx = ll_name_to_index(d)) == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", d); return 1; } req.t.tcm_ifindex = idx; } if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) return 2; return 0; }
/* Return value becomes exitcode. It's okay to not return at all */ static int ipaddr_modify(int cmd, int argc, char **argv) { static const char option[] ALIGN1 = "peer\0""remote\0""broadcast\0""brd\0" "anycast\0""scope\0""dev\0""label\0""local\0"; struct rtnl_handle rth; struct { struct nlmsghdr n; struct ifaddrmsg ifa; char buf[256]; } req; char *d = NULL; char *l = NULL; inet_prefix lcl; inet_prefix peer; int local_len = 0; int peer_len = 0; int brd_len = 0; int any_len = 0; bool scoped = 0; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = cmd; req.ifa.ifa_family = preferred_family; while (argc > 0) { const int option_num = index_in_strings(option, *argv); switch (option_num) { case 0: /* peer */ case 1: /* remote */ NEXT_ARG(); if (peer_len) { duparg("peer", *argv); } get_prefix(&peer, *argv, req.ifa.ifa_family); peer_len = peer.bytelen; if (req.ifa.ifa_family == AF_UNSPEC) { req.ifa.ifa_family = peer.family; } addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &peer.data, peer.bytelen); req.ifa.ifa_prefixlen = peer.bitlen; break; case 2: /* broadcast */ case 3: /* brd */ { inet_prefix addr; NEXT_ARG(); if (brd_len) { duparg("broadcast", *argv); } if (LONE_CHAR(*argv, '+')) { brd_len = -1; } else if (LONE_DASH(*argv)) { brd_len = -2; } else { get_addr(&addr, *argv, req.ifa.ifa_family); if (req.ifa.ifa_family == AF_UNSPEC) req.ifa.ifa_family = addr.family; addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &addr.data, addr.bytelen); brd_len = addr.bytelen; } break; } case 4: /* anycast */ { inet_prefix addr; NEXT_ARG(); if (any_len) { duparg("anycast", *argv); } get_addr(&addr, *argv, req.ifa.ifa_family); if (req.ifa.ifa_family == AF_UNSPEC) { req.ifa.ifa_family = addr.family; } addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen); any_len = addr.bytelen; break; } case 5: /* scope */ { uint32_t scope = 0; NEXT_ARG(); if (rtnl_rtscope_a2n(&scope, *argv)) { invarg(*argv, "scope"); } req.ifa.ifa_scope = scope; scoped = 1; break; } case 6: /* dev */ NEXT_ARG(); d = *argv; break; case 7: /* label */ NEXT_ARG(); l = *argv; addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1); break; case 8: /* local */ NEXT_ARG(); default: if (local_len) { duparg2("local", *argv); } get_prefix(&lcl, *argv, req.ifa.ifa_family); if (req.ifa.ifa_family == AF_UNSPEC) { req.ifa.ifa_family = lcl.family; } addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen); local_len = lcl.bytelen; } argc--; argv++; } if (d == NULL) { bb_error_msg(bb_msg_requires_arg,"\"dev\""); return -1; } if (l && strncmp(d, l, strlen(d)) != 0) { bb_error_msg_and_die("\"dev\" (%s) must match \"label\" (%s)", d, l); } if (peer_len == 0 && local_len && cmd != RTM_DELADDR) { peer = lcl; addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &lcl.data, lcl.bytelen); } if (req.ifa.ifa_prefixlen == 0) req.ifa.ifa_prefixlen = lcl.bitlen; if (brd_len < 0 && cmd != RTM_DELADDR) { inet_prefix brd; int i; if (req.ifa.ifa_family != AF_INET) { bb_error_msg_and_die("broadcast can be set only for IPv4 addresses"); } brd = peer; if (brd.bitlen <= 30) { for (i=31; i>=brd.bitlen; i--) { if (brd_len == -1) brd.data[0] |= htonl(1<<(31-i)); else brd.data[0] &= ~htonl(1<<(31-i)); } addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &brd.data, brd.bytelen); brd_len = brd.bytelen; } } if (!scoped && cmd != RTM_DELADDR) req.ifa.ifa_scope = default_scope(&lcl); xrtnl_open(&rth); ll_init_map(&rth); req.ifa.ifa_index = xll_name_to_index(d); if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) return 2; return 0; }
static int mdb_modify(int cmd, int flags, int argc, char **argv) { struct { struct nlmsghdr n; struct br_port_msg bpm; char buf[1024]; } req; struct br_mdb_entry entry; char *d = NULL, *p = NULL, *grp = NULL; memset(&req, 0, sizeof(req)); memset(&entry, 0, sizeof(entry)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_port_msg)); req.n.nlmsg_flags = NLM_F_REQUEST|flags; req.n.nlmsg_type = cmd; req.bpm.family = PF_BRIDGE; while (argc > 0) { if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); d = *argv; } else if (strcmp(*argv, "grp") == 0) { NEXT_ARG(); grp = *argv; } else if (strcmp(*argv, "port") == 0) { NEXT_ARG(); p = *argv; } else if (strcmp(*argv, "permanent") == 0) { if (cmd == RTM_NEWMDB) entry.state |= MDB_PERMANENT; } else if (strcmp(*argv, "temp") == 0) { ;/* nothing */ } else { if (matches(*argv, "help") == 0) usage(); } argc--; argv++; } if (d == NULL || grp == NULL || p == NULL) { fprintf(stderr, "Device, group address and port name are required arguments.\n"); exit(-1); } req.bpm.ifindex = ll_name_to_index(d); if (req.bpm.ifindex == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", d); return -1; } entry.ifindex = ll_name_to_index(p); if (entry.ifindex == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", p); return -1; } if (!inet_pton(AF_INET, grp, &entry.addr.u.ip4)) { if (!inet_pton(AF_INET6, grp, &entry.addr.u.ip6)) { fprintf(stderr, "Invalid address \"%s\"\n", grp); return -1; } else entry.addr.proto = htons(ETH_P_IPV6); } else entry.addr.proto = htons(ETH_P_IP); addattr_l(&req.n, sizeof(req), MDBA_SET_ENTRY, &entry, sizeof(entry)); if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) exit(2); return 0; }
static int ipaddr_modify(int cmd, int argc, char **argv) { const char *option[] = { "peer", "remote", "broadcast", "brd", "anycast", "scope", "dev", "label", "local", 0 }; struct rtnl_handle rth; struct { struct nlmsghdr n; struct ifaddrmsg ifa; char buf[256]; } req; char *d = NULL; char *l = NULL; inet_prefix lcl; inet_prefix peer; int local_len = 0; int peer_len = 0; int brd_len = 0; int any_len = 0; int scoped = 0; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = cmd; req.ifa.ifa_family = preferred_family; while (argc > 0) { const unsigned short option_num = compare_string_array(option, *argv); switch (option_num) { case 0: /* peer */ case 1: /* remote */ NEXT_ARG(); if (peer_len) { duparg("peer", *argv); } get_prefix(&peer, *argv, req.ifa.ifa_family); peer_len = peer.bytelen; if (req.ifa.ifa_family == AF_UNSPEC) { req.ifa.ifa_family = peer.family; } addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &peer.data, peer.bytelen); req.ifa.ifa_prefixlen = peer.bitlen; break; case 2: /* broadcast */ case 3: /* brd */ { inet_prefix addr; NEXT_ARG(); if (brd_len) { duparg("broadcast", *argv); } if (strcmp(*argv, "+") == 0) { brd_len = -1; } else if (strcmp(*argv, "-") == 0) { brd_len = -2; } else { get_addr(&addr, *argv, req.ifa.ifa_family); if (req.ifa.ifa_family == AF_UNSPEC) req.ifa.ifa_family = addr.family; addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &addr.data, addr.bytelen); brd_len = addr.bytelen; } break; } case 4: /* anycast */ { inet_prefix addr; NEXT_ARG(); if (any_len) { duparg("anycast", *argv); } get_addr(&addr, *argv, req.ifa.ifa_family); if (req.ifa.ifa_family == AF_UNSPEC) { req.ifa.ifa_family = addr.family; } addattr_l(&req.n, sizeof(req), IFA_ANYCAST, &addr.data, addr.bytelen); any_len = addr.bytelen; break; } case 5: /* scope */ { int scope = 0; NEXT_ARG(); if (rtnl_rtscope_a2n(&scope, *argv)) { invarg(*argv, "invalid scope value."); } req.ifa.ifa_scope = scope; scoped = 1; break; } case 6: /* dev */ NEXT_ARG(); d = *argv; break; case 7: /* label */ NEXT_ARG(); l = *argv; addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1); break; case 8: /* local */ NEXT_ARG(); default: if (local_len) { duparg2("local", *argv); } get_prefix(&lcl, *argv, req.ifa.ifa_family); if (req.ifa.ifa_family == AF_UNSPEC) { req.ifa.ifa_family = lcl.family; } addattr_l(&req.n, sizeof(req), IFA_LOCAL, &lcl.data, lcl.bytelen); local_len = lcl.bytelen; } argc--; argv++; } if (d == NULL) { bb_error_msg("Not enough information: \"dev\" argument is required."); return -1; } if (l && matches(d, l) != 0) { bb_error_msg_and_die("\"dev\" (%s) must match \"label\" (%s).", d, l); } if (peer_len == 0 && local_len && cmd != RTM_DELADDR) { peer = lcl; addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &lcl.data, lcl.bytelen); } if (req.ifa.ifa_prefixlen == 0) req.ifa.ifa_prefixlen = lcl.bitlen; if (brd_len < 0 && cmd != RTM_DELADDR) { inet_prefix brd; int i; if (req.ifa.ifa_family != AF_INET) { bb_error_msg("Broadcast can be set only for IPv4 addresses"); return -1; } brd = peer; if (brd.bitlen <= 30) { for (i=31; i>=brd.bitlen; i--) { if (brd_len == -1) brd.data[0] |= htonl(1<<(31-i)); else brd.data[0] &= ~htonl(1<<(31-i)); } addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &brd.data, brd.bytelen); brd_len = brd.bytelen; } } if (!scoped && cmd != RTM_DELADDR) req.ifa.ifa_scope = default_scope(&lcl); if (rtnl_open(&rth, 0) < 0) exit(1); ll_init_map(&rth); if ((req.ifa.ifa_index = ll_name_to_index(d)) == 0) { bb_error_msg("Cannot find device \"%s\"", d); return -1; } if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) exit(2); exit(0); }
static int iprule_modify(int cmd, int argc, char **argv) { int table_ok = 0; struct { struct nlmsghdr n; struct rtmsg r; char buf[1024]; } req; memset(&req, 0, sizeof(req)); req.n.nlmsg_type = cmd; req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.r.rtm_family = preferred_family; req.r.rtm_protocol = RTPROT_BOOT; req.r.rtm_scope = RT_SCOPE_UNIVERSE; req.r.rtm_table = 0; req.r.rtm_type = RTN_UNSPEC; req.r.rtm_flags = 0; if (cmd == RTM_NEWRULE) { req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL; req.r.rtm_type = RTN_UNICAST; } while (argc > 0) { if (strcmp(*argv, "not") == 0) { req.r.rtm_flags |= FIB_RULE_INVERT; } else if (strcmp(*argv, "from") == 0) { inet_prefix dst; NEXT_ARG(); get_prefix(&dst, *argv, req.r.rtm_family); req.r.rtm_src_len = dst.bitlen; addattr_l(&req.n, sizeof(req), FRA_SRC, &dst.data, dst.bytelen); } else if (strcmp(*argv, "to") == 0) { inet_prefix dst; NEXT_ARG(); get_prefix(&dst, *argv, req.r.rtm_family); req.r.rtm_dst_len = dst.bitlen; addattr_l(&req.n, sizeof(req), FRA_DST, &dst.data, dst.bytelen); } else if (matches(*argv, "preference") == 0 || matches(*argv, "order") == 0 || matches(*argv, "priority") == 0) { __u32 pref; NEXT_ARG(); if (get_u32(&pref, *argv, 0)) invarg("preference value is invalid\n", *argv); addattr32(&req.n, sizeof(req), FRA_PRIORITY, pref); } else if (strcmp(*argv, "tos") == 0) { __u32 tos; NEXT_ARG(); if (rtnl_dsfield_a2n(&tos, *argv)) invarg("TOS value is invalid\n", *argv); req.r.rtm_tos = tos; } else if (strcmp(*argv, "fwmark") == 0) { char *slash; __u32 fwmark, fwmask; NEXT_ARG(); if ((slash = strchr(*argv, '/')) != NULL) *slash = '\0'; if (get_u32(&fwmark, *argv, 0)) invarg("fwmark value is invalid\n", *argv); addattr32(&req.n, sizeof(req), FRA_FWMARK, fwmark); if (slash) { if (get_u32(&fwmask, slash+1, 0)) invarg("fwmask value is invalid\n", slash+1); addattr32(&req.n, sizeof(req), FRA_FWMASK, fwmask); } } else if (matches(*argv, "realms") == 0) { __u32 realm; NEXT_ARG(); if (get_rt_realms(&realm, *argv)) invarg("invalid realms\n", *argv); addattr32(&req.n, sizeof(req), FRA_FLOW, realm); } else if (matches(*argv, "table") == 0 || strcmp(*argv, "lookup") == 0) { __u32 tid; NEXT_ARG(); if (rtnl_rttable_a2n(&tid, *argv)) invarg("invalid table ID\n", *argv); if (tid < 256) req.r.rtm_table = tid; else { req.r.rtm_table = RT_TABLE_UNSPEC; addattr32(&req.n, sizeof(req), FRA_TABLE, tid); } table_ok = 1; } else if (strcmp(*argv, "dev") == 0 || strcmp(*argv, "iif") == 0) { NEXT_ARG(); addattr_l(&req.n, sizeof(req), FRA_IFNAME, *argv, strlen(*argv)+1); } else if (strcmp(*argv, "nat") == 0 || matches(*argv, "map-to") == 0) { NEXT_ARG(); fprintf(stderr, "Warning: route NAT is deprecated\n"); addattr32(&req.n, sizeof(req), RTA_GATEWAY, get_addr32(*argv)); req.r.rtm_type = RTN_NAT; } else { int type; if (strcmp(*argv, "type") == 0) { NEXT_ARG(); } if (matches(*argv, "help") == 0) usage(); else if (matches(*argv, "goto") == 0) { __u32 target; type = FR_ACT_GOTO; NEXT_ARG(); if (get_u32(&target, *argv, 0)) invarg("invalid target\n", *argv); addattr32(&req.n, sizeof(req), FRA_GOTO, target); } else if (matches(*argv, "nop") == 0) type = FR_ACT_NOP; else if (rtnl_rtntype_a2n(&type, *argv)) invarg("Failed to parse rule type", *argv); req.r.rtm_type = type; table_ok = 1; } argc--; argv++; } if (req.r.rtm_family == AF_UNSPEC) req.r.rtm_family = AF_INET; if (!table_ok && cmd == RTM_NEWRULE) req.r.rtm_table = RT_TABLE_MAIN; if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) return 2; return 0; }
static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { struct { struct nlmsghdr n; struct ifinfomsg i; char buf[2048]; } req; struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); struct rtattr *tb[IFLA_MAX + 1]; struct rtattr *linkinfo[IFLA_INFO_MAX+1]; struct rtattr *iptuninfo[IFLA_IPTUN_MAX + 1]; int len; __u32 link = 0; __u32 laddr = 0; __u32 raddr = 0; __u8 ttl = 0; __u8 tos = 0; __u8 pmtudisc = 1; __u16 iflags = 0; __u8 proto = 0; struct in6_addr ip6rdprefix; __u16 ip6rdprefixlen = 0; __u32 ip6rdrelayprefix = 0; __u16 ip6rdrelayprefixlen = 0; memset(&ip6rdprefix, 0, sizeof(ip6rdprefix)); if (!(n->nlmsg_flags & NLM_F_CREATE)) { memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_GETLINK; req.i.ifi_family = preferred_family; req.i.ifi_index = ifi->ifi_index; if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) { get_failed: fprintf(stderr, "Failed to get existing tunnel info.\n"); return -1; } len = req.n.nlmsg_len; len -= NLMSG_LENGTH(sizeof(*ifi)); if (len < 0) goto get_failed; parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len); if (!tb[IFLA_LINKINFO]) goto get_failed; parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]); if (!linkinfo[IFLA_INFO_DATA]) goto get_failed; parse_rtattr_nested(iptuninfo, IFLA_IPTUN_MAX, linkinfo[IFLA_INFO_DATA]); if (iptuninfo[IFLA_IPTUN_LOCAL]) laddr = rta_getattr_u32(iptuninfo[IFLA_IPTUN_LOCAL]); if (iptuninfo[IFLA_IPTUN_REMOTE]) raddr = rta_getattr_u32(iptuninfo[IFLA_IPTUN_REMOTE]); if (iptuninfo[IFLA_IPTUN_TTL]) ttl = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TTL]); if (iptuninfo[IFLA_IPTUN_TOS]) tos = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TOS]); if (iptuninfo[IFLA_IPTUN_PMTUDISC]) pmtudisc = rta_getattr_u8(iptuninfo[IFLA_IPTUN_PMTUDISC]); if (iptuninfo[IFLA_IPTUN_FLAGS]) iflags = rta_getattr_u16(iptuninfo[IFLA_IPTUN_FLAGS]); if (iptuninfo[IFLA_IPTUN_LINK]) link = rta_getattr_u32(iptuninfo[IFLA_IPTUN_LINK]); if (iptuninfo[IFLA_IPTUN_PROTO]) proto = rta_getattr_u8(iptuninfo[IFLA_IPTUN_PROTO]); if (iptuninfo[IFLA_IPTUN_6RD_PREFIX]) memcpy(&ip6rdprefix, RTA_DATA(iptuninfo[IFLA_IPTUN_6RD_PREFIX]), sizeof(laddr)); if (iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN]) ip6rdprefixlen = rta_getattr_u16(iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN]); if (iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX]) ip6rdrelayprefix = rta_getattr_u32(iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX]); if (iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]) ip6rdrelayprefixlen = rta_getattr_u16(iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]); } while (argc > 0) { if (strcmp(*argv, "remote") == 0) { NEXT_ARG(); if (strcmp(*argv, "any")) raddr = get_addr32(*argv); else raddr = 0; } else if (strcmp(*argv, "local") == 0) { NEXT_ARG(); if (strcmp(*argv, "any")) laddr = get_addr32(*argv); else laddr = 0; } else if (matches(*argv, "dev") == 0) { NEXT_ARG(); link = if_nametoindex(*argv); if (link == 0) invarg("\"dev\" is invalid", *argv); } else if (strcmp(*argv, "ttl") == 0 || strcmp(*argv, "hoplimit") == 0) { NEXT_ARG(); if (strcmp(*argv, "inherit") != 0) { if (get_u8(&ttl, *argv, 0)) invarg("invalid TTL\n", *argv); } else ttl = 0; } else if (strcmp(*argv, "tos") == 0 || strcmp(*argv, "tclass") == 0 || matches(*argv, "dsfield") == 0) { __u32 uval; NEXT_ARG(); if (strcmp(*argv, "inherit") != 0) { if (rtnl_dsfield_a2n(&uval, *argv)) invarg("bad TOS value", *argv); tos = uval; } else tos = 1; } else if (strcmp(*argv, "nopmtudisc") == 0) { pmtudisc = 0; } else if (strcmp(*argv, "pmtudisc") == 0) { pmtudisc = 1; } else if (strcmp(lu->id, "sit") == 0 && strcmp(*argv, "isatap") == 0) { iflags |= SIT_ISATAP; } else if (strcmp(lu->id, "sit") == 0 && strcmp(*argv, "mode") == 0) { NEXT_ARG(); if (strcmp(*argv, "ipv6/ipv4") == 0 || strcmp(*argv, "ip6ip") == 0) proto = IPPROTO_IPV6; else if (strcmp(*argv, "ipv4/ipv4") == 0 || strcmp(*argv, "ipip") == 0 || strcmp(*argv, "ip4ip4") == 0) proto = IPPROTO_IPIP; else if (strcmp(*argv, "any/ipv4") == 0 || strcmp(*argv, "any") == 0) proto = 0; else invarg("Cannot guess tunnel mode.", *argv); } else if (strcmp(*argv, "6rd-prefix") == 0) { inet_prefix prefix; NEXT_ARG(); if (get_prefix(&prefix, *argv, AF_INET6)) invarg("invalid 6rd_prefix\n", *argv); memcpy(&ip6rdprefix, prefix.data, 16); ip6rdprefixlen = prefix.bitlen; } else if (strcmp(*argv, "6rd-relay_prefix") == 0) { inet_prefix prefix; NEXT_ARG(); if (get_prefix(&prefix, *argv, AF_INET)) invarg("invalid 6rd-relay_prefix\n", *argv); memcpy(&ip6rdrelayprefix, prefix.data, 4); ip6rdrelayprefixlen = prefix.bitlen; } else if (strcmp(*argv, "6rd-reset") == 0) { inet_prefix prefix; get_prefix(&prefix, "2002::", AF_INET6); memcpy(&ip6rdprefix, prefix.data, 16); ip6rdprefixlen = 16; ip6rdrelayprefix = 0; ip6rdrelayprefixlen = 0; } else usage(strcmp(lu->id, "sit") == 0); argc--, argv++; } if (ttl && pmtudisc == 0) { fprintf(stderr, "ttl != 0 and nopmtudisc are incompatible\n"); exit(-1); } addattr32(n, 1024, IFLA_IPTUN_LINK, link); addattr32(n, 1024, IFLA_IPTUN_LOCAL, laddr); addattr32(n, 1024, IFLA_IPTUN_REMOTE, raddr); addattr8(n, 1024, IFLA_IPTUN_TTL, ttl); addattr8(n, 1024, IFLA_IPTUN_TOS, tos); addattr8(n, 1024, IFLA_IPTUN_PMTUDISC, pmtudisc); if (strcmp(lu->id, "sit") == 0) { addattr16(n, 1024, IFLA_IPTUN_FLAGS, iflags); addattr8(n, 1024, IFLA_IPTUN_PROTO, proto); if (ip6rdprefixlen) { addattr_l(n, 1024, IFLA_IPTUN_6RD_PREFIX, &ip6rdprefix, sizeof(ip6rdprefix)); addattr16(n, 1024, IFLA_IPTUN_6RD_PREFIXLEN, ip6rdprefixlen); addattr32(n, 1024, IFLA_IPTUN_6RD_RELAY_PREFIX, ip6rdrelayprefix); addattr16(n, 1024, IFLA_IPTUN_6RD_RELAY_PREFIXLEN, ip6rdrelayprefixlen); } } return 0; }
/* Return value becomes exitcode. It's okay to not return at all */ static int do_add_or_delete(char **argv, const unsigned rtm) { static const char keywords[] ALIGN1 = "link\0""name\0""type\0""dev\0""address\0"; enum { ARG_link, ARG_name, ARG_type, ARG_dev, ARG_address, }; struct rtnl_handle rth; struct { struct nlmsghdr n; struct ifinfomsg i; char buf[1024]; } req; smalluint arg; char *name_str = NULL; char *link_str = NULL; char *type_str = NULL; char *dev_str = NULL; char *address_str = NULL; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = rtm; req.i.ifi_family = preferred_family; if (rtm == RTM_NEWLINK) req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL; while (*argv) { arg = index_in_substrings(keywords, *argv); if (arg == ARG_type) { NEXT_ARG(); type_str = *argv++; dbg("type_str:'%s'", type_str); break; } if (arg == ARG_link) { NEXT_ARG(); link_str = *argv; dbg("link_str:'%s'", link_str); } else if (arg == ARG_name) { NEXT_ARG(); name_str = *argv; dbg("name_str:'%s'", name_str); } else if (arg == ARG_address) { NEXT_ARG(); address_str = *argv; dbg("address_str:'%s'", name_str); } else { if (arg == ARG_dev) { if (dev_str) duparg(*argv, "dev"); NEXT_ARG(); } dev_str = *argv; dbg("dev_str:'%s'", dev_str); } argv++; } xrtnl_open(&rth); ll_init_map(&rth); if (type_str) { struct rtattr *linkinfo = NLMSG_TAIL(&req.n); addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type_str, strlen(type_str)); if (*argv) { struct rtattr *data = NLMSG_TAIL(&req.n); addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0); if (strcmp(type_str, "vlan") == 0) vlan_parse_opt(argv, &req.n, sizeof(req)); data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; } linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; } if (rtm != RTM_NEWLINK) { if (!dev_str) return 1; /* Need a device to delete */ req.i.ifi_index = xll_name_to_index(dev_str); } else { if (!name_str) name_str = dev_str; if (link_str) { int idx = xll_name_to_index(link_str); addattr_l(&req.n, sizeof(req), IFLA_LINK, &idx, 4); } if (address_str) { unsigned char abuf[32]; int len = ll_addr_a2n(abuf, sizeof(abuf), address_str); dbg("address len:%d", len); if (len < 0) return -1; addattr_l(&req.n, sizeof(req), IFLA_ADDRESS, abuf, len); } } if (name_str) { const size_t name_len = strlen(name_str) + 1; if (name_len < 2 || name_len > IFNAMSIZ) invarg(name_str, "name"); addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name_str, name_len); } if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) return 2; return 0; }
static int gre_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { struct { struct nlmsghdr n; struct ifinfomsg i; char buf[1024]; } req; struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1); struct rtattr *tb[IFLA_MAX + 1]; struct rtattr *linkinfo[IFLA_INFO_MAX+1]; struct rtattr *greinfo[IFLA_GRE_MAX + 1]; __u16 iflags = 0; __u16 oflags = 0; unsigned ikey = 0; unsigned okey = 0; struct in6_addr raddr = IN6ADDR_ANY_INIT; struct in6_addr laddr = IN6ADDR_ANY_INIT; unsigned link = 0; unsigned flowinfo = 0; unsigned flags = 0; __u8 hop_limit = DEFAULT_TNL_HOP_LIMIT; __u8 encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT; int len; if (!(n->nlmsg_flags & NLM_F_CREATE)) { memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_GETLINK; req.i.ifi_family = preferred_family; req.i.ifi_index = ifi->ifi_index; if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) { get_failed: fprintf(stderr, "Failed to get existing tunnel info.\n"); return -1; } len = req.n.nlmsg_len; len -= NLMSG_LENGTH(sizeof(*ifi)); if (len < 0) goto get_failed; parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len); if (!tb[IFLA_LINKINFO]) goto get_failed; parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]); if (!linkinfo[IFLA_INFO_DATA]) goto get_failed; parse_rtattr_nested(greinfo, IFLA_GRE_MAX, linkinfo[IFLA_INFO_DATA]); if (greinfo[IFLA_GRE_IKEY]) ikey = rta_getattr_u32(greinfo[IFLA_GRE_IKEY]); if (greinfo[IFLA_GRE_OKEY]) okey = rta_getattr_u32(greinfo[IFLA_GRE_OKEY]); if (greinfo[IFLA_GRE_IFLAGS]) iflags = rta_getattr_u16(greinfo[IFLA_GRE_IFLAGS]); if (greinfo[IFLA_GRE_OFLAGS]) oflags = rta_getattr_u16(greinfo[IFLA_GRE_OFLAGS]); if (greinfo[IFLA_GRE_LOCAL]) memcpy(&laddr, RTA_DATA(greinfo[IFLA_GRE_LOCAL]), sizeof(laddr)); if (greinfo[IFLA_GRE_REMOTE]) memcpy(&raddr, RTA_DATA(greinfo[IFLA_GRE_REMOTE]), sizeof(raddr)); if (greinfo[IFLA_GRE_TTL]) hop_limit = rta_getattr_u8(greinfo[IFLA_GRE_TTL]); if (greinfo[IFLA_GRE_LINK]) link = rta_getattr_u32(greinfo[IFLA_GRE_LINK]); if (greinfo[IFLA_GRE_ENCAP_LIMIT]) encap_limit = rta_getattr_u8(greinfo[IFLA_GRE_ENCAP_LIMIT]); if (greinfo[IFLA_GRE_FLOWINFO]) flowinfo = rta_getattr_u32(greinfo[IFLA_GRE_FLOWINFO]); if (greinfo[IFLA_GRE_FLAGS]) flags = rta_getattr_u32(greinfo[IFLA_GRE_FLAGS]); } while (argc > 0) { if (!matches(*argv, "key")) { unsigned uval; NEXT_ARG(); iflags |= GRE_KEY; oflags |= GRE_KEY; if (strchr(*argv, '.')) uval = get_addr32(*argv); else { if (get_unsigned(&uval, *argv, 0) < 0) { fprintf(stderr, "Invalid value for \"key\"\n"); exit(-1); } uval = htonl(uval); } ikey = okey = uval; } else if (!matches(*argv, "ikey")) { unsigned uval; NEXT_ARG(); iflags |= GRE_KEY; if (strchr(*argv, '.')) uval = get_addr32(*argv); else { if (get_unsigned(&uval, *argv, 0)<0) { fprintf(stderr, "invalid value of \"ikey\"\n"); exit(-1); } uval = htonl(uval); } ikey = uval; } else if (!matches(*argv, "okey")) { unsigned uval; NEXT_ARG(); oflags |= GRE_KEY; if (strchr(*argv, '.')) uval = get_addr32(*argv); else { if (get_unsigned(&uval, *argv, 0)<0) { fprintf(stderr, "invalid value of \"okey\"\n"); exit(-1); } uval = htonl(uval); } okey = uval; } else if (!matches(*argv, "seq")) { iflags |= GRE_SEQ; oflags |= GRE_SEQ; } else if (!matches(*argv, "iseq")) { iflags |= GRE_SEQ; } else if (!matches(*argv, "oseq")) { oflags |= GRE_SEQ; } else if (!matches(*argv, "csum")) { iflags |= GRE_CSUM; oflags |= GRE_CSUM; } else if (!matches(*argv, "icsum")) { iflags |= GRE_CSUM; } else if (!matches(*argv, "ocsum")) { oflags |= GRE_CSUM; } else if (!matches(*argv, "remote")) { inet_prefix addr; NEXT_ARG(); get_prefix(&addr, *argv, preferred_family); if (addr.family == AF_UNSPEC) invarg("\"remote\" address family is AF_UNSPEC", *argv); memcpy(&raddr, &addr.data, sizeof(raddr)); } else if (!matches(*argv, "local")) { inet_prefix addr; NEXT_ARG(); get_prefix(&addr, *argv, preferred_family); if (addr.family == AF_UNSPEC) invarg("\"local\" address family is AF_UNSPEC", *argv); memcpy(&laddr, &addr.data, sizeof(laddr)); } else if (!matches(*argv, "dev")) { NEXT_ARG(); link = if_nametoindex(*argv); if (link == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", *argv); exit(-1); } } else if (!matches(*argv, "ttl") || !matches(*argv, "hoplimit")) { __u8 uval; NEXT_ARG(); if (get_u8(&uval, *argv, 0)) invarg("invalid TTL", *argv); hop_limit = uval; } else if (!matches(*argv, "tos") || !matches(*argv, "tclass") || !matches(*argv, "dsfield")) { __u8 uval; NEXT_ARG(); if (strcmp(*argv, "inherit") == 0) flags |= IP6_TNL_F_USE_ORIG_TCLASS; else { if (get_u8(&uval, *argv, 16)) invarg("invalid TClass", *argv); flowinfo |= htonl((__u32)uval << 20) & IP6_FLOWINFO_TCLASS; flags &= ~IP6_TNL_F_USE_ORIG_TCLASS; } } else if (strcmp(*argv, "flowlabel") == 0 || strcmp(*argv, "fl") == 0) { __u32 uval; NEXT_ARG(); if (strcmp(*argv, "inherit") == 0) flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL; else { if (get_u32(&uval, *argv, 16)) invarg("invalid Flowlabel", *argv); if (uval > 0xFFFFF) invarg("invalid Flowlabel", *argv); flowinfo |= htonl(uval) & IP6_FLOWINFO_FLOWLABEL; flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL; } } else if (strcmp(*argv, "dscp") == 0) { NEXT_ARG(); if (strcmp(*argv, "inherit") != 0) invarg("not inherit", *argv); flags |= IP6_TNL_F_RCV_DSCP_COPY; } else usage(); argc--; argv++; } addattr32(n, 1024, IFLA_GRE_IKEY, ikey); addattr32(n, 1024, IFLA_GRE_OKEY, okey); addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2); addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2); addattr_l(n, 1024, IFLA_GRE_LOCAL, &laddr, sizeof(laddr)); addattr_l(n, 1024, IFLA_GRE_REMOTE, &raddr, sizeof(raddr)); if (link) addattr32(n, 1024, IFLA_GRE_LINK, link); addattr_l(n, 1024, IFLA_GRE_TTL, &hop_limit, 1); addattr_l(n, 1024, IFLA_GRE_ENCAP_LIMIT, &encap_limit, 1); addattr_l(n, 1024, IFLA_GRE_FLOWINFO, &flowinfo, 4); addattr_l(n, 1024, IFLA_GRE_FLAGS, &flowinfo, 4); return 0; }
static int xfrm_state_allocspi(int argc, char **argv) { struct rtnl_handle rth; struct { struct nlmsghdr n; struct xfrm_userspi_info xspi; char buf[RTA_BUF_SIZE]; } req; char *idp = NULL; char *minp = NULL; char *maxp = NULL; struct xfrm_mark mark = {0, 0}; char res_buf[NLMSG_BUF_SIZE]; struct nlmsghdr *res_n = (struct nlmsghdr *)res_buf; memset(res_buf, 0, sizeof(res_buf)); memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xspi)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = XFRM_MSG_ALLOCSPI; req.xspi.info.family = preferred_family; #if 0 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; #endif while (argc > 0) { if (strcmp(*argv, "mode") == 0) { NEXT_ARG(); xfrm_mode_parse(&req.xspi.info.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.xspi.info.reqid, &argc, &argv); } else if (strcmp(*argv, "seq") == 0) { NEXT_ARG(); xfrm_seq_parse(&req.xspi.info.seq, &argc, &argv); } else if (strcmp(*argv, "min") == 0) { if (minp) duparg("min", *argv); minp = *argv; NEXT_ARG(); if (get_u32(&req.xspi.min, *argv, 0)) invarg("\"min\" value is invalid", *argv); } else if (strcmp(*argv, "max") == 0) { if (maxp) duparg("max", *argv); maxp = *argv; NEXT_ARG(); if (get_u32(&req.xspi.max, *argv, 0)) invarg("\"max\" value is invalid", *argv); } else { /* try to assume ID */ if (idp) invarg("unknown", *argv); idp = *argv; /* ID */ xfrm_id_parse(&req.xspi.info.saddr, &req.xspi.info.id, &req.xspi.info.family, 0, &argc, &argv); if (req.xspi.info.id.spi) { fprintf(stderr, "\"SPI\" must be zero\n"); exit(1); } if (preferred_family == AF_UNSPEC) preferred_family = req.xspi.info.family; } argc--; argv++; } if (!idp) { fprintf(stderr, "Not enough information: \"ID\" is required\n"); exit(1); } if (minp) { if (!maxp) { fprintf(stderr, "\"max\" is missing\n"); exit(1); } if (req.xspi.min > req.xspi.max) { fprintf(stderr, "\"min\" value is larger than \"max\" value\n"); exit(1); } } else { if (maxp) { fprintf(stderr, "\"min\" is missing\n"); exit(1); } /* XXX: Default value defined in PF_KEY; * See kernel's net/key/af_key.c(pfkey_getspi). */ req.xspi.min = 0x100; req.xspi.max = 0x0fffffff; /* XXX: IPCOMP spi is 16-bits; * See kernel's net/xfrm/xfrm_user(verify_userspi_info). */ if (req.xspi.info.id.proto == IPPROTO_COMP) req.xspi.max = 0xffff; } 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); } } if (rtnl_open_byproto(&rth, 0, NETLINK_XFRM) < 0) exit(1); if (req.xspi.info.family == AF_UNSPEC) req.xspi.info.family = AF_INET; if (rtnl_talk(&rth, &req.n, 0, 0, res_n) < 0) exit(2); if (xfrm_state_print(NULL, res_n, (void*)stdout) < 0) { fprintf(stderr, "An error :-)\n"); exit(1); } rtnl_close(&rth); return 0; }