static int get_response(struct nlmsghdr *n, void *arg) { struct genlmsghdr *ghdr; struct l2tp_data *data = arg; struct l2tp_parm *p = &data->config; struct rtattr *attrs[L2TP_ATTR_MAX + 1]; struct rtattr *nla_stats; int len; /* Validate message and parse attributes */ if (n->nlmsg_type == NLMSG_ERROR) return -EBADMSG; ghdr = NLMSG_DATA(n); len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*ghdr)); if (len < 0) return -1; parse_rtattr(attrs, L2TP_ATTR_MAX, (void *)ghdr + GENL_HDRLEN, len); if (attrs[L2TP_ATTR_PW_TYPE]) p->pw_type = rta_getattr_u16(attrs[L2TP_ATTR_PW_TYPE]); if (attrs[L2TP_ATTR_ENCAP_TYPE]) p->encap = rta_getattr_u16(attrs[L2TP_ATTR_ENCAP_TYPE]); if (attrs[L2TP_ATTR_OFFSET]) p->offset = rta_getattr_u16(attrs[L2TP_ATTR_OFFSET]); if (attrs[L2TP_ATTR_DATA_SEQ]) p->data_seq = rta_getattr_u16(attrs[L2TP_ATTR_DATA_SEQ]); if (attrs[L2TP_ATTR_CONN_ID]) p->tunnel_id = rta_getattr_u32(attrs[L2TP_ATTR_CONN_ID]); if (attrs[L2TP_ATTR_PEER_CONN_ID]) p->peer_tunnel_id = rta_getattr_u32(attrs[L2TP_ATTR_PEER_CONN_ID]); if (attrs[L2TP_ATTR_SESSION_ID]) p->session_id = rta_getattr_u32(attrs[L2TP_ATTR_SESSION_ID]); if (attrs[L2TP_ATTR_PEER_SESSION_ID]) p->peer_session_id = rta_getattr_u32(attrs[L2TP_ATTR_PEER_SESSION_ID]); if (attrs[L2TP_ATTR_L2SPEC_TYPE]) p->l2spec_type = rta_getattr_u8(attrs[L2TP_ATTR_L2SPEC_TYPE]); if (attrs[L2TP_ATTR_L2SPEC_LEN]) p->l2spec_len = rta_getattr_u8(attrs[L2TP_ATTR_L2SPEC_LEN]); if (attrs[L2TP_ATTR_UDP_CSUM]) p->udp_csum = !!rta_getattr_u8(attrs[L2TP_ATTR_UDP_CSUM]); p->udp6_csum_tx = !attrs[L2TP_ATTR_UDP_ZERO_CSUM6_TX]; p->udp6_csum_rx = !attrs[L2TP_ATTR_UDP_ZERO_CSUM6_RX]; if (attrs[L2TP_ATTR_COOKIE]) memcpy(p->cookie, RTA_DATA(attrs[L2TP_ATTR_COOKIE]), p->cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_COOKIE])); if (attrs[L2TP_ATTR_PEER_COOKIE]) memcpy(p->peer_cookie, RTA_DATA(attrs[L2TP_ATTR_PEER_COOKIE]), p->peer_cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_PEER_COOKIE])); if (attrs[L2TP_ATTR_RECV_SEQ]) p->recv_seq = !!rta_getattr_u8(attrs[L2TP_ATTR_RECV_SEQ]); if (attrs[L2TP_ATTR_SEND_SEQ]) p->send_seq = !!rta_getattr_u8(attrs[L2TP_ATTR_SEND_SEQ]); if (attrs[L2TP_ATTR_RECV_TIMEOUT]) p->reorder_timeout = rta_getattr_u64(attrs[L2TP_ATTR_RECV_TIMEOUT]); if (attrs[L2TP_ATTR_IP_SADDR]) { p->local_ip.family = AF_INET; p->local_ip.data[0] = rta_getattr_u32(attrs[L2TP_ATTR_IP_SADDR]); p->local_ip.bytelen = 4; p->local_ip.bitlen = -1; } if (attrs[L2TP_ATTR_IP_DADDR]) { p->peer_ip.family = AF_INET; p->peer_ip.data[0] = rta_getattr_u32(attrs[L2TP_ATTR_IP_DADDR]); p->peer_ip.bytelen = 4; p->peer_ip.bitlen = -1; } if (attrs[L2TP_ATTR_IP6_SADDR]) { p->local_ip.family = AF_INET6; memcpy(&p->local_ip.data, RTA_DATA(attrs[L2TP_ATTR_IP6_SADDR]), p->local_ip.bytelen = 16); p->local_ip.bitlen = -1; } if (attrs[L2TP_ATTR_IP6_DADDR]) { p->peer_ip.family = AF_INET6; memcpy(&p->peer_ip.data, RTA_DATA(attrs[L2TP_ATTR_IP6_DADDR]), p->peer_ip.bytelen = 16); p->peer_ip.bitlen = -1; } if (attrs[L2TP_ATTR_UDP_SPORT]) p->local_udp_port = rta_getattr_u16(attrs[L2TP_ATTR_UDP_SPORT]); if (attrs[L2TP_ATTR_UDP_DPORT]) p->peer_udp_port = rta_getattr_u16(attrs[L2TP_ATTR_UDP_DPORT]); if (attrs[L2TP_ATTR_MTU]) p->mtu = rta_getattr_u16(attrs[L2TP_ATTR_MTU]); if (attrs[L2TP_ATTR_IFNAME]) p->ifname = rta_getattr_str(attrs[L2TP_ATTR_IFNAME]); nla_stats = attrs[L2TP_ATTR_STATS]; if (nla_stats) { struct rtattr *tb[L2TP_ATTR_STATS_MAX + 1]; parse_rtattr_nested(tb, L2TP_ATTR_STATS_MAX, nla_stats); if (tb[L2TP_ATTR_TX_PACKETS]) data->stats.data_tx_packets = rta_getattr_u64(tb[L2TP_ATTR_TX_PACKETS]); if (tb[L2TP_ATTR_TX_BYTES]) data->stats.data_tx_bytes = rta_getattr_u64(tb[L2TP_ATTR_TX_BYTES]); if (tb[L2TP_ATTR_TX_ERRORS]) data->stats.data_tx_errors = rta_getattr_u64(tb[L2TP_ATTR_TX_ERRORS]); if (tb[L2TP_ATTR_RX_PACKETS]) data->stats.data_rx_packets = rta_getattr_u64(tb[L2TP_ATTR_RX_PACKETS]); if (tb[L2TP_ATTR_RX_BYTES]) data->stats.data_rx_bytes = rta_getattr_u64(tb[L2TP_ATTR_RX_BYTES]); if (tb[L2TP_ATTR_RX_ERRORS]) data->stats.data_rx_errors = rta_getattr_u64(tb[L2TP_ATTR_RX_ERRORS]); if (tb[L2TP_ATTR_RX_SEQ_DISCARDS]) data->stats.data_rx_oos_discards = rta_getattr_u64(tb[L2TP_ATTR_RX_SEQ_DISCARDS]); if (tb[L2TP_ATTR_RX_OOS_PACKETS]) data->stats.data_rx_oos_packets = rta_getattr_u64(tb[L2TP_ATTR_RX_OOS_PACKETS]); } return 0; }
int genl_ctrl_resolve_family(const char *family) { struct rtnl_handle rth; struct nlmsghdr *nlh; struct genlmsghdr *ghdr; int ret = 0; struct { struct nlmsghdr n; char buf[4096]; } req; memset(&req, 0, sizeof(req)); nlh = &req.n; nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; nlh->nlmsg_type = GENL_ID_CTRL; ghdr = NLMSG_DATA(&req.n); ghdr->cmd = CTRL_CMD_GETFAMILY; if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) { fprintf(stderr, "Cannot open generic netlink socket\n"); exit(1); } addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME, family, strlen(family) + 1); if (rtnl_talk(&rth, nlh, nlh, sizeof(req)) < 0) { fprintf(stderr, "Error talking to the kernel\n"); goto errout; } { struct rtattr *tb[CTRL_ATTR_MAX + 1]; struct genlmsghdr *ghdr = NLMSG_DATA(nlh); int len = nlh->nlmsg_len; struct rtattr *attrs; if (nlh->nlmsg_type != GENL_ID_CTRL) { fprintf(stderr, "Not a controller message, nlmsg_len=%d " "nlmsg_type=0x%x\n", nlh->nlmsg_len, nlh->nlmsg_type); goto errout; } if (ghdr->cmd != CTRL_CMD_NEWFAMILY) { fprintf(stderr, "Unknown controller command %d\n", ghdr->cmd); goto errout; } len -= NLMSG_LENGTH(GENL_HDRLEN); if (len < 0) { fprintf(stderr, "wrong controller message len %d\n", len); return -1; } attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN); parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len); if (tb[CTRL_ATTR_FAMILY_ID] == NULL) { fprintf(stderr, "Missing family id TLV\n"); goto errout; } ret = rta_getattr_u16(tb[CTRL_ATTR_FAMILY_ID]); } errout: rtnl_close(&rth); return ret; }
static int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv) { struct qdisc_util *q = NULL; struct tc_estimator est; struct { struct tc_sizespec szopts; __u16 *data; } stab; 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(&stab, 0, sizeof(stab)); 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("invalid qdisc ID", *argv); 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("invalid parent ID", *argv); req.t.tcm_parent = handle; } else if (matches(*argv, "estimator") == 0) { if (parse_estimator(&argc, &argv, &est)) return -1; } else if (matches(*argv, "stab") == 0) { if (parse_size_table(&argc, &argv, &stab.szopts) < 0) return -1; continue; } 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) { if (q->parse_qopt(q, argc, argv, &req.n)) return 1; } else if (argc) { fprintf(stderr, "qdisc '%s' does not support option parsing\n", k); 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 (check_size_table_opts(&stab.szopts)) { struct rtattr *tail; if (tc_calc_size_table(&stab.szopts, &stab.data) < 0) { fprintf(stderr, "failed to calculate size table.\n"); return -1; } tail = NLMSG_TAIL(&req.n); addattr_l(&req.n, sizeof(req), TCA_STAB, NULL, 0); addattr_l(&req.n, sizeof(req), TCA_STAB_BASE, &stab.szopts, sizeof(stab.szopts)); if (stab.data) addattr_l(&req.n, sizeof(req), TCA_STAB_DATA, stab.data, stab.szopts.tsize * sizeof(__u16)); tail->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)tail; if (stab.data) free(stab.data); } 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) < 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; unsigned saddr = 0; unsigned daddr = 0; unsigned link = 0; __u8 pmtudisc = 1; __u8 ttl = 0; __u8 tos = 0; 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, NULL, NULL) < 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 = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_IKEY]); if (greinfo[IFLA_GRE_OKEY]) okey = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_OKEY]); if (greinfo[IFLA_GRE_IFLAGS]) iflags = *(__u16 *)RTA_DATA(greinfo[IFLA_GRE_IFLAGS]); if (greinfo[IFLA_GRE_OFLAGS]) oflags = *(__u16 *)RTA_DATA(greinfo[IFLA_GRE_OFLAGS]); if (greinfo[IFLA_GRE_LOCAL]) saddr = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_LOCAL]); if (greinfo[IFLA_GRE_REMOTE]) daddr = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_REMOTE]); if (greinfo[IFLA_GRE_PMTUDISC]) pmtudisc = *(__u8 *)RTA_DATA( greinfo[IFLA_GRE_PMTUDISC]); if (greinfo[IFLA_GRE_TTL]) ttl = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_TTL]); if (greinfo[IFLA_GRE_TOS]) tos = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_TOS]); if (greinfo[IFLA_GRE_LINK]) link = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_LINK]); } 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, "nopmtudisc")) { pmtudisc = 0; } else if (!matches(*argv, "pmtudisc")) { pmtudisc = 1; } else if (!matches(*argv, "remote")) { NEXT_ARG(); if (strcmp(*argv, "any")) daddr = get_addr32(*argv); } else if (!matches(*argv, "local")) { NEXT_ARG(); if (strcmp(*argv, "any")) saddr = get_addr32(*argv); } else if (!matches(*argv, "dev")) { NEXT_ARG(); link = tnl_ioctl_get_ifindex(*argv); if (link == 0) exit(-1); } else if (!matches(*argv, "ttl") || !matches(*argv, "hoplimit")) { unsigned uval; NEXT_ARG(); if (strcmp(*argv, "inherit") != 0) { if (get_unsigned(&uval, *argv, 0)) invarg("invalid TTL\n", *argv); if (uval > 255) invarg("TTL must be <= 255\n", *argv); ttl = uval; } } else if (!matches(*argv, "tos") || !matches(*argv, "tclass") || !matches(*argv, "dsfield")) { __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 usage(); argc--; argv++; } if (!ikey && IN_MULTICAST(ntohl(daddr))) { ikey = daddr; iflags |= GRE_KEY; } if (!okey && IN_MULTICAST(ntohl(daddr))) { okey = daddr; oflags |= GRE_KEY; } if (IN_MULTICAST(ntohl(daddr)) && !saddr) { fprintf(stderr, "Broadcast tunnel requires a source address.\n"); return -1; } 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, &saddr, 4); addattr_l(n, 1024, IFLA_GRE_REMOTE, &daddr, 4); addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &pmtudisc, 1); if (link) addattr32(n, 1024, IFLA_GRE_LINK, link); addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1); addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1); return 0; }
/* * The controller sends one nlmsg per family */ static int print_ctrl(const struct sockaddr_nl *who, struct rtnl_ctrl_data *ctrl, struct nlmsghdr *n, void *arg) { struct rtattr *tb[CTRL_ATTR_MAX + 1]; struct genlmsghdr *ghdr = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *attrs; FILE *fp = (FILE *) arg; __u32 ctrl_v = 0x1; if (n->nlmsg_type != GENL_ID_CTRL) { fprintf(stderr, "Not a controller message, nlmsg_len=%d " "nlmsg_type=0x%x\n", n->nlmsg_len, n->nlmsg_type); return 0; } if (ghdr->cmd != CTRL_CMD_GETFAMILY && ghdr->cmd != CTRL_CMD_DELFAMILY && ghdr->cmd != CTRL_CMD_NEWFAMILY && ghdr->cmd != CTRL_CMD_NEWMCAST_GRP && ghdr->cmd != CTRL_CMD_DELMCAST_GRP) { fprintf(stderr, "Unknown controller command %d\n", ghdr->cmd); return 0; } len -= NLMSG_LENGTH(GENL_HDRLEN); if (len < 0) { fprintf(stderr, "wrong controller message len %d\n", len); return -1; } attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN); parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len); if (tb[CTRL_ATTR_FAMILY_NAME]) { char *name = RTA_DATA(tb[CTRL_ATTR_FAMILY_NAME]); fprintf(fp, "\nName: %s\n",name); } if (tb[CTRL_ATTR_FAMILY_ID]) { __u16 *id = RTA_DATA(tb[CTRL_ATTR_FAMILY_ID]); fprintf(fp, "\tID: 0x%x ",*id); } if (tb[CTRL_ATTR_VERSION]) { __u32 *v = RTA_DATA(tb[CTRL_ATTR_VERSION]); fprintf(fp, " Version: 0x%x ",*v); ctrl_v = *v; } if (tb[CTRL_ATTR_HDRSIZE]) { __u32 *h = RTA_DATA(tb[CTRL_ATTR_HDRSIZE]); fprintf(fp, " header size: %d ",*h); } if (tb[CTRL_ATTR_MAXATTR]) { __u32 *ma = RTA_DATA(tb[CTRL_ATTR_MAXATTR]); fprintf(fp, " max attribs: %d ",*ma); } /* end of family definitions .. */ fprintf(fp,"\n"); if (tb[CTRL_ATTR_OPS]) { struct rtattr *tb2[GENL_MAX_FAM_OPS]; int i=0; parse_rtattr_nested(tb2, GENL_MAX_FAM_OPS, tb[CTRL_ATTR_OPS]); fprintf(fp, "\tcommands supported: \n"); for (i = 0; i < GENL_MAX_FAM_OPS; i++) { if (tb2[i]) { fprintf(fp, "\t\t#%d: ", i); if (0 > print_ctrl_cmds(fp, tb2[i], ctrl_v)) { fprintf(fp, "Error printing command\n"); } /* for next command */ fprintf(fp,"\n"); } } /* end of family::cmds definitions .. */ fprintf(fp,"\n"); } if (tb[CTRL_ATTR_MCAST_GROUPS]) { struct rtattr *tb2[GENL_MAX_FAM_GRPS + 1]; int i; parse_rtattr_nested(tb2, GENL_MAX_FAM_GRPS, tb[CTRL_ATTR_MCAST_GROUPS]); fprintf(fp, "\tmulticast groups:\n"); for (i = 0; i < GENL_MAX_FAM_GRPS; i++) { if (tb2[i]) { fprintf(fp, "\t\t#%d: ", i); if (0 > print_ctrl_grp(fp, tb2[i], ctrl_v)) fprintf(fp, "Error printing group\n"); /* for next group */ fprintf(fp,"\n"); } } /* end of family::groups definitions .. */ fprintf(fp,"\n"); } fflush(fp); return 0; }
/** * In case one binds to 0.0.0.0/INADDR_ANY and wants to know which source * address will be used when sending a message this function can be used. * It will ask the routing code of the kernel for the PREFSRC */ int source_for_dest(const struct in_addr *dest, struct in_addr *loc_source) { int fd, rc; struct rtmsg *r; struct rtattr *rta; struct { struct nlmsghdr n; struct rtmsg r; char buf[1024]; } req; memset(&req, 0, sizeof(req)); fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_ROUTE); if (fd < 0) { perror("nl socket"); return -1; } /* Send a rtmsg and ask for a response */ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; req.n.nlmsg_type = RTM_GETROUTE; req.n.nlmsg_seq = 1; /* Prepare the routing request */ req.r.rtm_family = AF_INET; /* set the dest */ rta = NLMSG_TAIL(&req.n); rta->rta_type = RTA_DST; rta->rta_len = RTA_LENGTH(sizeof(*dest)); memcpy(RTA_DATA(rta), dest, sizeof(*dest)); /* update sizes for dest */ req.r.rtm_dst_len = sizeof(*dest) * 8; req.n.nlmsg_len = NLMSG_ALIGN(req.n.nlmsg_len) + RTA_ALIGN(rta->rta_len); rc = send(fd, &req, req.n.nlmsg_len, 0); if (rc != req.n.nlmsg_len) { perror("short write"); close(fd); return -2; } /* now receive a response and parse it */ rc = recv(fd, &req, sizeof(req), 0); if (rc <= 0) { perror("short read"); close(fd); return -3; } if (!NLMSG_OK(&req.n, rc) || req.n.nlmsg_type != RTM_NEWROUTE) { close(fd); return -4; } r = NLMSG_DATA(&req.n); rc -= NLMSG_LENGTH(sizeof(*r)); rta = RTM_RTA(r); while (RTA_OK(rta, rc)) { if (rta->rta_type != RTA_PREFSRC) { rta = RTA_NEXT(rta, rc); continue; } /* we are done */ memcpy(loc_source, RTA_DATA(rta), RTA_PAYLOAD(rta)); close(fd); return 0; } close(fd); return -5; }
int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE*)arg; struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr * tb[RTA_MAX+1]; char abuf[256]; int host_len; __u32 table; SPRINT_BUF(b1); static int hz; if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) { fprintf(stderr, "Not a route: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); return 0; } if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE) return 0; len -= NLMSG_LENGTH(sizeof(*r)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } host_len = af_bit_len(r->rtm_family); parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); table = rtm_get_table(r, tb); if (!filter_nlmsg(n, tb, host_len)) return 0; if (filter.flushb) { struct nlmsghdr *fn; if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) { if (flush_update()) return -1; } fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp)); memcpy(fn, n, n->nlmsg_len); fn->nlmsg_type = RTM_DELROUTE; fn->nlmsg_flags = NLM_F_REQUEST; fn->nlmsg_seq = ++rth.seq; filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb; filter.flushed++; if (show_stats < 2) return 0; } if (n->nlmsg_type == RTM_DELROUTE) fprintf(fp, "Deleted "); if ((r->rtm_type != RTN_UNICAST || show_details > 0) && !filter.type) fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1))); if (tb[RTA_DST]) { if (r->rtm_dst_len != host_len) { fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[RTA_DST]), RTA_DATA(tb[RTA_DST]), abuf, sizeof(abuf)), r->rtm_dst_len ); } else { fprintf(fp, "%s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_DST]), RTA_DATA(tb[RTA_DST]), abuf, sizeof(abuf)) ); } } else if (r->rtm_dst_len) { fprintf(fp, "0/%d ", r->rtm_dst_len); } else { fprintf(fp, "default "); } if (tb[RTA_SRC]) { if (r->rtm_src_len != host_len) { fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[RTA_SRC]), RTA_DATA(tb[RTA_SRC]), abuf, sizeof(abuf)), r->rtm_src_len ); } else { fprintf(fp, "from %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_SRC]), RTA_DATA(tb[RTA_SRC]), abuf, sizeof(abuf)) ); } } else if (r->rtm_src_len) { fprintf(fp, "from 0/%u ", r->rtm_src_len); } if (tb[RTA_NEWDST]) { fprintf(fp, "as to %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_NEWDST]), RTA_DATA(tb[RTA_NEWDST]), abuf, sizeof(abuf)) ); } if (r->rtm_tos && filter.tosmask != -1) { SPRINT_BUF(b1); fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1))); } if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) { fprintf(fp, "via %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_GATEWAY]), RTA_DATA(tb[RTA_GATEWAY]), abuf, sizeof(abuf))); } if (tb[RTA_VIA]) { size_t len = RTA_PAYLOAD(tb[RTA_VIA]) - 2; struct rtvia *via = RTA_DATA(tb[RTA_VIA]); fprintf(fp, "via %s %s ", family_name(via->rtvia_family), format_host(via->rtvia_family, len, via->rtvia_addr, abuf, sizeof(abuf))); } if (tb[RTA_OIF] && filter.oifmask != -1) fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF]))); if (!(r->rtm_flags&RTM_F_CLONED)) { if ((table != RT_TABLE_MAIN || show_details > 0) && !filter.tb) fprintf(fp, " table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1))); if ((r->rtm_protocol != RTPROT_BOOT || show_details > 0) && filter.protocolmask != -1) fprintf(fp, " proto %s ", rtnl_rtprot_n2a(r->rtm_protocol, b1, sizeof(b1))); if ((r->rtm_scope != RT_SCOPE_UNIVERSE || show_details > 0) && filter.scopemask != -1) fprintf(fp, " scope %s ", rtnl_rtscope_n2a(r->rtm_scope, b1, sizeof(b1))); } if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) { /* Do not use format_host(). It is our local addr and symbolic name will not be useful. */ fprintf(fp, " src %s ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[RTA_PREFSRC]), RTA_DATA(tb[RTA_PREFSRC]), abuf, sizeof(abuf))); } if (tb[RTA_PRIORITY]) fprintf(fp, " metric %u ", rta_getattr_u32(tb[RTA_PRIORITY])); if (r->rtm_flags & RTNH_F_DEAD) fprintf(fp, "dead "); if (r->rtm_flags & RTNH_F_ONLINK) fprintf(fp, "onlink "); if (r->rtm_flags & RTNH_F_PERVASIVE) fprintf(fp, "pervasive "); if (r->rtm_flags & RTNH_F_EXTERNAL) fprintf(fp, "offload "); if (r->rtm_flags & RTM_F_NOTIFY) fprintf(fp, "notify "); if (tb[RTA_MARK]) { unsigned int mark = *(unsigned int*)RTA_DATA(tb[RTA_MARK]); if (mark) { if (mark >= 16) fprintf(fp, " mark 0x%x", mark); else fprintf(fp, " mark %u", mark); } } if (tb[RTA_FLOW] && filter.realmmask != ~0U) { __u32 to = rta_getattr_u32(tb[RTA_FLOW]); __u32 from = to>>16; to &= 0xFFFF; fprintf(fp, "realm%s ", from ? "s" : ""); if (from) { fprintf(fp, "%s/", rtnl_rtrealm_n2a(from, b1, sizeof(b1))); } fprintf(fp, "%s ", rtnl_rtrealm_n2a(to, b1, sizeof(b1))); }
int netlink_link_add_vmac(vrrp_t *vrrp) { struct rtattr *linkinfo; struct rtattr *data; unsigned int base_ifindex; interface_t *ifp; interface_t *base_ifp; char ifname[IFNAMSIZ]; struct { struct nlmsghdr n; struct ifinfomsg ifi; char buf[256]; } req; if (!vrrp->ifp || __test_bit(VRRP_VMAC_UP_BIT, &vrrp->vmac_flags) || !vrrp->vrid) return -1; if (vrrp->family == AF_INET6) ll_addr[4] = 0x02; else ll_addr[4] = 0x01; ll_addr[ETH_ALEN-1] = vrrp->vrid; memset(&req, 0, sizeof (req)); memset(ifname, 0, IFNAMSIZ); strncpy(ifname, vrrp->vmac_ifname, IFNAMSIZ - 1); /* * Check to see if this vmac interface was created * by a previous instance. */ if ((ifp = if_get_by_ifname(ifname))) { /* Check to see whether this interface has wrong mac ? */ if (memcmp((const void *) ifp->hw_addr, (const void *) ll_addr, ETH_ALEN) != 0) { /* We have found a VIF but the vmac do not match */ log_message(LOG_INFO, "vmac: Removing old VMAC interface %s due to conflicting " "interface MAC for vrrp_instance %s!!!" , vrrp->vmac_ifname, vrrp->iname); /* Request that NETLINK remove the VIF interface first */ 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_DELLINK; req.ifi.ifi_family = AF_INET; req.ifi.ifi_index = IF_INDEX(ifp); if (netlink_talk(&nl_cmd, &req.n) < 0) { log_message(LOG_INFO, "vmac: Error removing VMAC interface %s for " "vrrp_instance %s!!!" , vrrp->vmac_ifname, vrrp->iname); return -1; } /* Interface successfully removed, now recreate */ } } /* Request that NETLINK create the VIF interface */ req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct ifinfomsg)); req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; req.n.nlmsg_type = RTM_NEWLINK; req.ifi.ifi_family = AF_INET; /* macvlan settings */ linkinfo = NLMSG_TAIL(&req.n); addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, (void *)macvlan_ll_kind, strlen(macvlan_ll_kind)); data = NLMSG_TAIL(&req.n); addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0); /* * In private mode, macvlan will receive frames with same MAC addr * as configured on the interface. */ addattr32(&req.n, sizeof(req), IFLA_MACVLAN_MODE, MACVLAN_MODE_PRIVATE); data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; addattr_l(&req.n, sizeof(req), IFLA_LINK, &IF_INDEX(vrrp->ifp), sizeof(uint32_t)); addattr_l(&req.n, sizeof(req), IFLA_IFNAME, ifname, strlen(ifname)); addattr_l(&req.n, sizeof(req), IFLA_ADDRESS, ll_addr, ETH_ALEN); if (netlink_talk(&nl_cmd, &req.n) < 0) { log_message(LOG_INFO, "vmac: Error creating VMAC interface %s for vrrp_instance %s!!!" , ifname, vrrp->iname); return -1; } log_message(LOG_INFO, "vmac: Success creating VMAC interface %s for vrrp_instance %s" , ifname, vrrp->iname); /* * Update interface queue and vrrp instance interface binding. */ netlink_interface_lookup(); ifp = if_get_by_ifname(ifname); if (!ifp) return -1; base_ifp = vrrp->ifp; base_ifindex = vrrp->ifp->ifindex; ifp->flags = vrrp->ifp->flags; /* Copy base interface flags */ vrrp->ifp = ifp; vrrp->ifp->base_ifindex = base_ifindex; vrrp->ifp->vmac = 1; vrrp->vmac_ifindex = IF_INDEX(vrrp->ifp); /* For use on delete */ if (vrrp->family == AF_INET) { /* Set the necessary kernel parameters to make macvlans work for us */ set_interface_parameters(ifp, base_ifp); /* We don't want IPv6 running on the interface unless we have some IPv6 * eVIPs, so disable it if not needed */ if (!vrrp->evip_add_ipv6) link_disable_ipv6(ifp); } if (vrrp->family == AF_INET6 || vrrp->evip_add_ipv6) { // We don't want a link-local address auto assigned - see RFC5798 paragraph 7.4. // If we have a sufficiently recent kernel, we can stop a link local address // based on the MAC address being automatically assigned. If not, then we have // to delete the generated address after bringing the interface up (see below). #ifdef IFLA_INET6_ADDR_GEN_MODE /* Since Linux 3.17 */ 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_NEWLINK; req.ifi.ifi_family = AF_UNSPEC; req.ifi.ifi_index = vrrp->vmac_ifindex; u_char val = IN6_ADDR_GEN_MODE_NONE; struct rtattr* spec; spec = NLMSG_TAIL(&req.n); addattr_l(&req.n, sizeof(req), IFLA_AF_SPEC, NULL,0); data = NLMSG_TAIL(&req.n); addattr_l(&req.n, sizeof(req), AF_INET6, NULL,0); addattr_l(&req.n, sizeof(req), IFLA_INET6_ADDR_GEN_MODE, &val, sizeof(val)); data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; spec->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)spec; if (netlink_talk(&nl_cmd, &req.n) < 0) log_message(LOG_INFO, "vmac: Error setting ADDR_GEN_MODE to NONE"); #endif if (vrrp->family == AF_INET6) { /* Add link-local address. If a source address has been specified, use it, * else use link-local address from underlying interface to vmac if there is one, * otherwise construct a link-local address based on underlying interface's * MAC address. * This is so that VRRP advertisements will be sent from a non-VIP address, but * using the VRRP MAC address */ ip_address_t ipaddress; memset(&ipaddress, 0, sizeof(ipaddress)); ipaddress.ifp = ifp; if (vrrp->saddr.ss_family == AF_INET6) ipaddress.u.sin6_addr = ((struct sockaddr_in6*)&vrrp->saddr)->sin6_addr; else if (base_ifp->sin6_addr.s6_addr32[0]) ipaddress.u.sin6_addr = base_ifp->sin6_addr; else make_link_local_address(&ipaddress.u.sin6_addr, base_ifp->hw_addr); ipaddress.ifa.ifa_family = AF_INET6; ipaddress.ifa.ifa_prefixlen = 64; ipaddress.ifa.ifa_index = vrrp->vmac_ifindex; if (netlink_ipaddress(&ipaddress, IPADDRESS_ADD) != 1) log_message(LOG_INFO, "Adding link-local address to vmac failed"); /* Save the address as source for vrrp packets */ if (vrrp->saddr.ss_family == AF_UNSPEC) inet_ip6tosockaddr(&ipaddress.u.sin6_addr, &vrrp->saddr); inet_ip6scopeid(vrrp->vmac_ifindex, &vrrp->saddr); } } /* bring it UP ! */ __set_bit(VRRP_VMAC_UP_BIT, &vrrp->vmac_flags); netlink_link_up(vrrp); #ifndef IFLA_INET6_ADDR_GEN_MODE if (vrrp->family == AF_INET6 || vrrp->evip_add_ipv6) { /* Delete the automatically created link-local address based on the * MAC address if we weren't able to configure the interface not to * create the address (see above). * This isn't ideal, since the invalid address will exist momentarily, * but is there any better way to do it? probably not otherwise * ADDR_GEN_MODE wouldn't have been added to the kernel. */ ip_address_t ipaddress; memset(&ipaddress, 0, sizeof(ipaddress)); ipaddress.u.sin6_addr = base_ifp->sin6_addr; make_link_local_address(&ipaddress.u.sin6_addr, ll_addr); ipaddress.ifa.ifa_family = AF_INET6; ipaddress.ifa.ifa_prefixlen = 64; ipaddress.ifa.ifa_index = vrrp->vmac_ifindex; if (netlink_ipaddress(&ipaddress, IPADDRESS_DEL) != 1) log_message(LOG_INFO, "Deleting auto link-local address from vmac failed"); } #endif return 1; }
int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE*)arg; struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr * tb[RTA_MAX+1]; char abuf[256]; inet_prefix dst; inet_prefix src; inet_prefix prefsrc; inet_prefix via; int host_len = -1; static int ip6_multiple_tables; __u32 table; SPRINT_BUF(b1); static int hz; if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) { fprintf(stderr, "Not a route: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); return 0; } if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE) return 0; len -= NLMSG_LENGTH(sizeof(*r)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } if (r->rtm_family == AF_INET6) host_len = 128; else if (r->rtm_family == AF_INET) host_len = 32; else if (r->rtm_family == AF_DECnet) host_len = 16; else if (r->rtm_family == AF_IPX) host_len = 80; parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); table = rtm_get_table(r, tb); if (r->rtm_family == AF_INET6 && table != RT_TABLE_MAIN) ip6_multiple_tables = 1; if (filter.cloned == !(r->rtm_flags&RTM_F_CLONED)) return 0; if (r->rtm_family == AF_INET6 && !ip6_multiple_tables) { if (filter.tb) { if (filter.tb == RT_TABLE_LOCAL) { if (r->rtm_type != RTN_LOCAL) return 0; } else if (filter.tb == RT_TABLE_MAIN) { if (r->rtm_type == RTN_LOCAL) return 0; } else { return 0; } } } else { if (filter.tb > 0 && filter.tb != table) return 0; } if ((filter.protocol^r->rtm_protocol)&filter.protocolmask) return 0; if ((filter.scope^r->rtm_scope)&filter.scopemask) return 0; if ((filter.type^r->rtm_type)&filter.typemask) return 0; if ((filter.tos^r->rtm_tos)&filter.tosmask) return 0; if (filter.rdst.family && (r->rtm_family != filter.rdst.family || filter.rdst.bitlen > r->rtm_dst_len)) return 0; if (filter.mdst.family && (r->rtm_family != filter.mdst.family || (filter.mdst.bitlen >= 0 && filter.mdst.bitlen < r->rtm_dst_len))) return 0; if (filter.rsrc.family && (r->rtm_family != filter.rsrc.family || filter.rsrc.bitlen > r->rtm_src_len)) return 0; if (filter.msrc.family && (r->rtm_family != filter.msrc.family || (filter.msrc.bitlen >= 0 && filter.msrc.bitlen < r->rtm_src_len))) return 0; if (filter.rvia.family && r->rtm_family != filter.rvia.family) return 0; if (filter.rprefsrc.family && r->rtm_family != filter.rprefsrc.family) return 0; memset(&dst, 0, sizeof(dst)); dst.family = r->rtm_family; if (tb[RTA_DST]) memcpy(&dst.data, RTA_DATA(tb[RTA_DST]), (r->rtm_dst_len+7)/8); if (filter.rsrc.family || filter.msrc.family) { memset(&src, 0, sizeof(src)); src.family = r->rtm_family; if (tb[RTA_SRC]) memcpy(&src.data, RTA_DATA(tb[RTA_SRC]), (r->rtm_src_len+7)/8); } if (filter.rvia.bitlen>0) { memset(&via, 0, sizeof(via)); via.family = r->rtm_family; if (tb[RTA_GATEWAY]) memcpy(&via.data, RTA_DATA(tb[RTA_GATEWAY]), host_len/8); } if (filter.rprefsrc.bitlen>0) { memset(&prefsrc, 0, sizeof(prefsrc)); prefsrc.family = r->rtm_family; if (tb[RTA_PREFSRC]) memcpy(&prefsrc.data, RTA_DATA(tb[RTA_PREFSRC]), host_len/8); } if (filter.rdst.family && inet_addr_match(&dst, &filter.rdst, filter.rdst.bitlen)) return 0; if (filter.mdst.family && filter.mdst.bitlen >= 0 && inet_addr_match(&dst, &filter.mdst, r->rtm_dst_len)) return 0; if (filter.rsrc.family && inet_addr_match(&src, &filter.rsrc, filter.rsrc.bitlen)) return 0; if (filter.msrc.family && filter.msrc.bitlen >= 0 && inet_addr_match(&src, &filter.msrc, r->rtm_src_len)) return 0; if (filter.rvia.family && inet_addr_match(&via, &filter.rvia, filter.rvia.bitlen)) return 0; if (filter.rprefsrc.family && inet_addr_match(&prefsrc, &filter.rprefsrc, filter.rprefsrc.bitlen)) return 0; if (filter.realmmask) { __u32 realms = 0; if (tb[RTA_FLOW]) realms = *(__u32*)RTA_DATA(tb[RTA_FLOW]); if ((realms^filter.realm)&filter.realmmask) return 0; } if (filter.iifmask) { int iif = 0; if (tb[RTA_IIF]) iif = *(int*)RTA_DATA(tb[RTA_IIF]); if ((iif^filter.iif)&filter.iifmask) return 0; } if (filter.oifmask) { int oif = 0; if (tb[RTA_OIF]) oif = *(int*)RTA_DATA(tb[RTA_OIF]); if ((oif^filter.oif)&filter.oifmask) return 0; } if (filter.flushb && r->rtm_family == AF_INET6 && r->rtm_dst_len == 0 && r->rtm_type == RTN_UNREACHABLE && tb[RTA_PRIORITY] && *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1) return 0; if (filter.flushb) { struct nlmsghdr *fn; if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) { if (flush_update()) return -1; } fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp)); memcpy(fn, n, n->nlmsg_len); fn->nlmsg_type = RTM_DELROUTE; fn->nlmsg_flags = NLM_F_REQUEST; fn->nlmsg_seq = ++rth.seq; filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb; filter.flushed++; if (show_stats < 2) return 0; } if (n->nlmsg_type == RTM_DELROUTE) fprintf(fp, "Deleted "); if (r->rtm_type != RTN_UNICAST && !filter.type) fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1))); if (tb[RTA_DST]) { if (r->rtm_dst_len != host_len) { fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[RTA_DST]), RTA_DATA(tb[RTA_DST]), abuf, sizeof(abuf)), r->rtm_dst_len ); } else { fprintf(fp, "%s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_DST]), RTA_DATA(tb[RTA_DST]), abuf, sizeof(abuf)) ); } } else if (r->rtm_dst_len) { fprintf(fp, "0/%d ", r->rtm_dst_len); } else { fprintf(fp, "default "); } if (tb[RTA_SRC]) { if (r->rtm_src_len != host_len) { fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[RTA_SRC]), RTA_DATA(tb[RTA_SRC]), abuf, sizeof(abuf)), r->rtm_src_len ); } else { fprintf(fp, "from %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_SRC]), RTA_DATA(tb[RTA_SRC]), abuf, sizeof(abuf)) ); } } else if (r->rtm_src_len) { fprintf(fp, "from 0/%u ", r->rtm_src_len); } if (r->rtm_tos && filter.tosmask != -1) { SPRINT_BUF(b1); fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1))); } if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) { fprintf(fp, "via %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_GATEWAY]), RTA_DATA(tb[RTA_GATEWAY]), abuf, sizeof(abuf))); } if (tb[RTA_OIF] && filter.oifmask != -1) fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF]))); if (!(r->rtm_flags&RTM_F_CLONED)) { if (table != RT_TABLE_MAIN && !filter.tb) fprintf(fp, " table %s ", rtnl_rttable_n2a(table, b1, sizeof(b1))); if (r->rtm_protocol != RTPROT_BOOT && filter.protocolmask != -1) fprintf(fp, " proto %s ", rtnl_rtprot_n2a(r->rtm_protocol, b1, sizeof(b1))); if (r->rtm_scope != RT_SCOPE_UNIVERSE && filter.scopemask != -1) fprintf(fp, " scope %s ", rtnl_rtscope_n2a(r->rtm_scope, b1, sizeof(b1))); } if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) { /* Do not use format_host(). It is our local addr and symbolic name will not be useful. */ fprintf(fp, " src %s ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[RTA_PREFSRC]), RTA_DATA(tb[RTA_PREFSRC]), abuf, sizeof(abuf))); } if (tb[RTA_PRIORITY]) fprintf(fp, " metric %d ", *(__u32*)RTA_DATA(tb[RTA_PRIORITY])); if (r->rtm_flags & RTNH_F_DEAD) fprintf(fp, "dead "); if (r->rtm_flags & RTNH_F_ONLINK) fprintf(fp, "onlink "); if (r->rtm_flags & RTNH_F_PERVASIVE) fprintf(fp, "pervasive "); if (r->rtm_flags & RTM_F_NOTIFY) fprintf(fp, "notify "); if (tb[RTA_FLOW] && filter.realmmask != ~0U) { __u32 to = *(__u32*)RTA_DATA(tb[RTA_FLOW]); __u32 from = to>>16; to &= 0xFFFF; fprintf(fp, "realm%s ", from ? "s" : ""); if (from) { fprintf(fp, "%s/", rtnl_rtrealm_n2a(from, b1, sizeof(b1))); } fprintf(fp, "%s ", rtnl_rtrealm_n2a(to, b1, sizeof(b1))); }
static void format_netlink(struct nlmsghdr *msg) { struct rtattr *tb[ACPI_GENL_ATTR_MAX + 1]; struct genlmsghdr *ghdr = NLMSG_DATA(msg); int len; struct rtattr *attrs; len = msg->nlmsg_len; /* if this message doesn't have the proper family ID, drop it */ if (msg->nlmsg_type != acpi_ids_getfamily()) { if (logevents) { acpid_log(LOG_INFO, "wrong netlink family ID.\n"); } return; } len -= NLMSG_LENGTH(GENL_HDRLEN); if (len < 0) { acpid_log(LOG_WARNING, "wrong netlink controller message len: %d\n", len); return; } attrs = (struct rtattr *)((char *)ghdr + GENL_HDRLEN); /* parse the attributes in this message */ parse_rtattr(tb, ACPI_GENL_ATTR_MAX, attrs, len); /* if there's an ACPI event attribute... */ if (tb[ACPI_GENL_ATTR_EVENT]) { /* get the actual event struct */ struct acpi_genl_event *event = RTA_DATA(tb[ACPI_GENL_ATTR_EVENT]); char buf[64]; /* format it */ snprintf(buf, sizeof(buf), "%s %s %08x %08x", event->device_class, event->bus_id, event->type, event->data); /* if we're locked, don't process the event */ if (locked()) { if (logevents) { acpid_log(LOG_INFO, "lockfile present, not processing " "netlink event \"%s\"\n", buf); } return; } if (logevents) acpid_log(LOG_INFO, "received netlink event \"%s\"\n", buf); /* send the event off to the handler */ acpid_handle_event(buf); if (logevents) acpid_log(LOG_INFO, "completed netlink event \"%s\"\n", buf); } }
static void recvaddrs(int fd, struct ifaddrs **ifa, __u32 seq) { char buf[8192]; struct sockaddr_nl nladdr; struct iovec iov = { buf, sizeof(buf) }; struct ifaddrmsg *m; struct rtattr * rta_tb[IFA_MAX+1]; struct ifaddrs *I; while (1) { int status; struct nlmsghdr *h; struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 }; status = recvmsg(fd, &msg, 0); if (status < 0) continue; if (status == 0) return; if (nladdr.nl_pid) /* Message not from kernel */ continue; h = (struct nlmsghdr*)buf; while (NLMSG_OK(h, status)) { if (h->nlmsg_seq != seq) goto skip_it; if (h->nlmsg_type == NLMSG_DONE) return; if (h->nlmsg_type == NLMSG_ERROR) return; if (h->nlmsg_type != RTM_NEWADDR) goto skip_it; m = NLMSG_DATA(h); if (m->ifa_family != AF_INET && m->ifa_family != AF_INET6) goto skip_it; if (m->ifa_flags&IFA_F_TENTATIVE) goto skip_it; memset(rta_tb, 0, sizeof(rta_tb)); parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(m), h->nlmsg_len - NLMSG_LENGTH(sizeof(*m))); if (rta_tb[IFA_LOCAL] == NULL) rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS]; if (rta_tb[IFA_LOCAL] == NULL) goto skip_it; I = malloc(sizeof(struct ifaddrs)); if (!I) return; memset(I, 0, sizeof(*I)); I->ifa_ifindex = m->ifa_index; I->ifa_addr = (struct sockaddr*)&I->ifa_addrbuf; I->ifa_addr->sa_family = m->ifa_family; if (m->ifa_family == AF_INET) { struct sockaddr_in *sin = (void*)I->ifa_addr; memcpy(&sin->sin_addr, RTA_DATA(rta_tb[IFA_LOCAL]), 4); } else { struct sockaddr_in6 *sin = (void*)I->ifa_addr; memcpy(&sin->sin6_addr, RTA_DATA(rta_tb[IFA_LOCAL]), 16); if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) sin->sin6_scope_id = I->ifa_ifindex; } I->ifa_next = *ifa; *ifa = I; skip_it: h = NLMSG_NEXT(h, status); } if (msg.msg_flags & MSG_TRUNC) continue; } return; }
static int xfrm_policy_keep(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { struct xfrm_buffer *xb = (struct xfrm_buffer *)arg; struct rtnl_handle *rth = xb->rth; struct xfrm_userpolicy_info *xpinfo = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr *tb[XFRMA_MAX+1]; __u8 ptype = XFRM_POLICY_TYPE_MAIN; struct nlmsghdr *new_n; struct xfrm_userpolicy_id *xpid; if (n->nlmsg_type != XFRM_MSG_NEWPOLICY) { fprintf(stderr, "Not a policy: %08x %08x %08x\n", n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); return 0; } len -= NLMSG_LENGTH(sizeof(*xpinfo)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } parse_rtattr(tb, XFRMA_MAX, XFRMP_RTA(xpinfo), len); if (tb[XFRMA_POLICY_TYPE]) { struct xfrm_userpolicy_type *upt; if (RTA_PAYLOAD(tb[XFRMA_POLICY_TYPE]) < sizeof(*upt)) { fprintf(stderr, "too short XFRMA_POLICY_TYPE len\n"); return -1; } upt = (struct xfrm_userpolicy_type *)RTA_DATA(tb[XFRMA_POLICY_TYPE]); ptype = upt->type; } if (!xfrm_policy_filter_match(xpinfo, ptype)) return 0; if (xb->offset > xb->size) { fprintf(stderr, "Policy buffer overflow\n"); return -1; } new_n = (struct nlmsghdr *)(xb->buf + xb->offset); new_n->nlmsg_len = NLMSG_LENGTH(sizeof(*xpid)); new_n->nlmsg_flags = NLM_F_REQUEST; new_n->nlmsg_type = XFRM_MSG_DELPOLICY; new_n->nlmsg_seq = ++rth->seq; xpid = NLMSG_DATA(new_n); memcpy(&xpid->sel, &xpinfo->sel, sizeof(xpid->sel)); xpid->dir = xpinfo->dir; xpid->index = xpinfo->index; xb->offset += new_n->nlmsg_len; xb->nlmsg_count ++; 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; char *sctxp = NULL; struct xfrm_userpolicy_type upt; char tmpls_buf[XFRM_TMPLS_BUF_SIZE]; int tmpls_len = 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(&upt, 0, sizeof(upt)); memset(&tmpls_buf, 0, sizeof(tmpls_buf)); memset(&ctx, 0, sizeof(ctx)); 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, "ctx") == 0) { char *context; if (sctxp) duparg("ctx", *argv); sctxp = *argv; NEXT_ARG(); context = *argv; xfrm_sctx_parse((char *)&ctx.str, context, &ctx.sctx); } else if (strcmp(*argv, "mark") == 0) { xfrm_parse_mark(&mark, &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 (mark.m & mark.v) { int r = addattr_l(&req.n, sizeof(req.buf), XFRMA_MARK, (void *)&mark, sizeof(mark)); if (r < 0) { fprintf(stderr, "%s: XFRMA_MARK failed\n",__func__); exit(1); } } if (sctxp) { addattr_l(&req.n, sizeof(req), XFRMA_SEC_CTX, (void *)&ctx, ctx.sctx.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) < 0) exit(2); rtnl_close(&rth); return 0; }
char *indexp = NULL; char *ptypep = NULL; char *sctxp = NULL; struct xfrm_userpolicy_type upt; 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(&upt, 0, sizeof(upt)); memset(&ctx, 0, sizeof(ctx)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.xpid)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = delete ? XFRM_MSG_DELPOLICY : XFRM_MSG_GETPOLICY; while (argc > 0) { if (strcmp(*argv, "dir") == 0) { if (dirp) duparg("dir", *argv); dirp = *argv; NEXT_ARG(); xfrm_policy_dir_parse(&req.xpid.dir, &argc, &argv); } else if (strcmp(*argv, "ctx") == 0) { char *context;
int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE*)arg; struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; int host_len = -1; __u32 table; struct rtattr * tb[FRA_MAX+1]; char abuf[256]; SPRINT_BUF(b1); if (n->nlmsg_type != RTM_NEWRULE && n->nlmsg_type != RTM_DELRULE) return 0; len -= NLMSG_LENGTH(sizeof(*r)); if (len < 0) return -1; parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len); if (r->rtm_family == AF_INET) host_len = 32; else if (r->rtm_family == AF_INET6) host_len = 128; else if (r->rtm_family == AF_DECnet) host_len = 16; else if (r->rtm_family == AF_IPX) host_len = 80; if (n->nlmsg_type == RTM_DELRULE) fprintf(fp, "Deleted "); if (tb[FRA_PRIORITY]) fprintf(fp, "%u:\t", *(unsigned*)RTA_DATA(tb[FRA_PRIORITY])); else fprintf(fp, "0:\t"); if (r->rtm_flags & FIB_RULE_INVERT) fprintf(fp, "not "); if (tb[FRA_SRC]) { if (r->rtm_src_len != host_len) { fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[FRA_SRC]), RTA_DATA(tb[FRA_SRC]), abuf, sizeof(abuf)), r->rtm_src_len ); } else { fprintf(fp, "from %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[FRA_SRC]), RTA_DATA(tb[FRA_SRC]), abuf, sizeof(abuf)) ); } } else if (r->rtm_src_len) { fprintf(fp, "from 0/%d ", r->rtm_src_len); } else { fprintf(fp, "from all "); } if (tb[FRA_DST]) { if (r->rtm_dst_len != host_len) { fprintf(fp, "to %s/%u ", rt_addr_n2a(r->rtm_family, RTA_PAYLOAD(tb[FRA_DST]), RTA_DATA(tb[FRA_DST]), abuf, sizeof(abuf)), r->rtm_dst_len ); } else { fprintf(fp, "to %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[FRA_DST]), RTA_DATA(tb[FRA_DST]), abuf, sizeof(abuf))); } } else if (r->rtm_dst_len) { fprintf(fp, "to 0/%d ", r->rtm_dst_len); } if (r->rtm_tos) { SPRINT_BUF(b1); fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1))); } if (tb[FRA_FWMARK] || tb[FRA_FWMASK]) { __u32 mark = 0, mask = 0; if (tb[FRA_FWMARK]) mark = rta_getattr_u32(tb[FRA_FWMARK]); if (tb[FRA_FWMASK] && (mask = rta_getattr_u32(tb[FRA_FWMASK])) != 0xFFFFFFFF) fprintf(fp, "fwmark 0x%x/0x%x ", mark, mask); else fprintf(fp, "fwmark 0x%x ", mark); } if (tb[FRA_IFNAME]) { fprintf(fp, "iif %s ", rta_getattr_str(tb[FRA_IFNAME])); if (r->rtm_flags & FIB_RULE_IIF_DETACHED) fprintf(fp, "[detached] "); } if (tb[FRA_OIFNAME]) { fprintf(fp, "oif %s ", rta_getattr_str(tb[FRA_OIFNAME])); if (r->rtm_flags & FIB_RULE_OIF_DETACHED) fprintf(fp, "[detached] "); } table = rtm_get_table(r, tb); if (table) fprintf(fp, "lookup %s ", rtnl_rttable_n2a(table, b1, sizeof(b1))); if (tb[FRA_FLOW]) { __u32 to = rta_getattr_u32(tb[FRA_FLOW]); __u32 from = to>>16; to &= 0xFFFF; if (from) { fprintf(fp, "realms %s/", rtnl_rtrealm_n2a(from, b1, sizeof(b1))); } fprintf(fp, "%s ", rtnl_rtrealm_n2a(to, b1, sizeof(b1))); } if (r->rtm_type == RTN_NAT) { if (tb[RTA_GATEWAY]) { fprintf(fp, "map-to %s ", format_host(r->rtm_family, RTA_PAYLOAD(tb[RTA_GATEWAY]), RTA_DATA(tb[RTA_GATEWAY]), abuf, sizeof(abuf))); } else fprintf(fp, "masquerade"); } else if (r->rtm_type == FR_ACT_GOTO) { fprintf(fp, "goto "); if (tb[FRA_GOTO]) fprintf(fp, "%u", rta_getattr_u32(tb[FRA_GOTO])); else fprintf(fp, "none"); if (r->rtm_flags & FIB_RULE_UNRESOLVED) fprintf(fp, " [unresolved]"); } else if (r->rtm_type == FR_ACT_NOP) fprintf(fp, "nop"); else if (r->rtm_type != RTN_UNICAST) fprintf(fp, "%s", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1))); fprintf(fp, "\n"); fflush(fp); return 0; }
/* * Adds or deletes an IP address on an interface. * * Action is one of: * - RTM_NEWADDR (to add a new address) * - RTM_DELADDR (to delete an existing address) * * Returns zero on success and negative errno on failure. */ int ifc_act_on_address(int action, const char *name, const char *address, int prefixlen) { int ifindex, s, len, ret; struct sockaddr_storage ss; void *addr; size_t addrlen; struct { struct nlmsghdr n; struct ifaddrmsg r; // Allow for IPv6 address, headers, and padding. char attrbuf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtattr)) + NLMSG_ALIGN(INET6_ADDRLEN)]; } req; struct rtattr *rta; struct nlmsghdr *nh; struct nlmsgerr *err; char buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct nlmsgerr)) + NLMSG_ALIGN(sizeof(struct nlmsghdr))]; // Get interface ID. ifindex = if_nametoindex(name); if (ifindex == 0) { return -errno; } // Convert string representation to sockaddr_storage. ret = string_to_ip(address, &ss); if (ret) { return ret; } // Determine address type and length. if (ss.ss_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *) &ss; addr = &sin->sin_addr; addrlen = INET_ADDRLEN; } else if (ss.ss_family == AF_INET6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &ss; addr = &sin6->sin6_addr; addrlen = INET6_ADDRLEN; } else { return -EAFNOSUPPORT; } // Fill in netlink structures. memset(&req, 0, sizeof(req)); // Netlink message header. req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.r)); req.n.nlmsg_type = action; req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; req.n.nlmsg_pid = getpid(); // Interface address message header. req.r.ifa_family = ss.ss_family; req.r.ifa_prefixlen = prefixlen; req.r.ifa_index = ifindex; // Routing attribute. Contains the actual IP address. rta = (struct rtattr *) (((char *) &req) + NLMSG_ALIGN(req.n.nlmsg_len)); rta->rta_type = IFA_LOCAL; rta->rta_len = RTA_LENGTH(addrlen); req.n.nlmsg_len = NLMSG_ALIGN(req.n.nlmsg_len) + RTA_LENGTH(addrlen); memcpy(RTA_DATA(rta), addr, addrlen); s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (send(s, &req, req.n.nlmsg_len, 0) < 0) { close(s); return -errno; } len = recv(s, buf, sizeof(buf), 0); close(s); if (len < 0) { return -errno; } // Parse the acknowledgement to find the return code. nh = (struct nlmsghdr *) buf; if (!NLMSG_OK(nh, (unsigned) len) || nh->nlmsg_type != NLMSG_ERROR) { return -EINVAL; } err = NLMSG_DATA(nh); // Return code is negative errno. return err->error; }
static int nl_getmsg (int sd, int request, int seq, struct nlmsghdr **nlhp, int *done) { struct nlmsghdr *nh; size_t bufsize = 65536, lastbufsize = 0; void *buff = NULL; int result = 0, read_size; int msg_flags; pid_t pid = getpid (); for (;;) { void *newbuff = realloc (buff, bufsize); if (newbuff == NULL || bufsize < lastbufsize) { result = -1; break; } buff = newbuff; result = read_size = nl_recvmsg (sd, request, seq, buff, bufsize, &msg_flags); if (read_size < 0 || (msg_flags & MSG_TRUNC)) { lastbufsize = bufsize; bufsize *= 2; continue; } if (read_size == 0) break; nh = (struct nlmsghdr *) buff; for (nh = (struct nlmsghdr *) buff; NLMSG_OK (nh, read_size); nh = (struct nlmsghdr *) NLMSG_NEXT (nh, read_size)) { if (nh->nlmsg_pid != pid || nh->nlmsg_seq != seq) continue; if (nh->nlmsg_type == NLMSG_DONE) { (*done)++; break; /* ok */ } if (nh->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *nlerr = (struct nlmsgerr *) NLMSG_DATA (nh); result = -1; if (nh->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr))) __set_errno (EIO); else __set_errno (-nlerr->error); break; } } break; } if (result < 0) if (buff) { int saved_errno = errno; free (buff); __set_errno (saved_errno); } *nlhp = (struct nlmsghdr *) buff; return result; }
int checkIpAddrTableChanges(PMIB_IPADDRTABLE pNew, PMIB_IPADDRTABLE pOld) { enum { IP_ADD, IP_DEL, IP_CHG, }; int i, max, ret = 0; if (!pNew || !pOld) { return(0); } max = (pNew->dwNumEntries > pOld->dwNumEntries) ? pNew->dwNumEntries : pOld->dwNumEntries; /* printf("IP table: ["); */ for (i = 0; i < max; i++) { /* printf("%u.%u.%u.%u(%d) ", NIPQUAD(pNew->table[i].dwAddr), */ /* (int)pNew->table[i].dwIndex); */ #ifdef __WIN32__ if ((pNew->table[i].dwAddr != pOld->table[i].dwAddr) || (pNew->table[i].wType != pOld->table[i].wType)) { if ((pNew->table[i].wType & MIB_IPADDR_DELETED) || ((pNew->table[i].wType & MIB_IPADDR_DISCONNECTED))) { netlink_send_addr(1, pOld->table[i].dwAddr, pOld->table[i].dwIndex); } #else if ((pNew->table[i].dwAddr != pOld->table[i].dwAddr) || (pNew->table[i].unused2 != pOld->table[i].unused2)) { /* unused2 is wType */ /* Address deleted due to flags */ if ((pNew->table[i].unused2 & MIB_IPADDR_DELETED) || ((pNew->table[i].unused2 & MIB_IPADDR_DISCONNECTED))) { netlink_send_addr(1, pOld->table[i].dwAddr, pOld->table[i].dwIndex); } #endif /* Address deleted, replaced by 0.0.0.0 */ else if ((pNew->table[i].dwAddr == 0) && (pOld->table[i].dwAddr) && (pOld->table[i].dwIndex == pNew->table[i].dwIndex)) { netlink_send_addr(1, pOld->table[i].dwAddr, pOld->table[i].dwIndex); } /* New address */ else { /* first delete old address, if any */ if ((pOld->table[i].dwAddr) && (pOld->table[i].dwIndex == pNew->table[i].dwIndex)) { netlink_send_addr( 1, pOld->table[i].dwAddr, pOld->table[i]. dwIndex); } /* send new address */ netlink_send_addr(0, pNew->table[i].dwAddr, pNew->table[i].dwIndex); } ret = 1; } } /* printf("]\n"); */ return(ret); } /* * 0 = add, 1 = deleted */ int netlink_send_addr(int add_del, DWORD addr, DWORD ifindex) { char buff[512]; int len; struct nlmsghdr *msg; struct ifaddrmsg *ifa; struct rtattr *rta; __u32 *p_addr; /* ignore 0.0.0.0 and 1.x.x.x */ if ((addr == 0) || (addr == g_tap_lsi)) { return(0); } /* printf("Address %u.%u.%u.%u has been ", NIPQUAD(addr)); * printf("%s.\n", add_del ? "deleted" : "added"); */ /* netlink message header */ memset(buff, 0, sizeof(buff)); msg = (struct nlmsghdr*) &buff[0]; len = NLMSG_LENGTH( sizeof(struct ifaddrmsg) + sizeof(struct rtattr) + sizeof(__u32)); msg->nlmsg_len = NLMSG_ALIGN(len); msg->nlmsg_type = add_del ? RTM_DELADDR : RTM_NEWADDR; msg->nlmsg_flags = 0; msg->nlmsg_seq = 0; msg->nlmsg_pid = 0; /* interface address message */ ifa = (struct ifaddrmsg*) NLMSG_DATA(msg); ifa->ifa_family = AF_INET; ifa->ifa_prefixlen = 32; ifa->ifa_flags = IFA_F_PERMANENT; ifa->ifa_scope = IFA_LOCAL; ifa->ifa_index = ifindex; /* route attributes */ rta = IFA_RTA(ifa); rta->rta_len = RTA_LENGTH(sizeof(__u32)); rta->rta_type = IFA_LOCAL; p_addr = (__u32*)(rta + 1); *p_addr = addr; /* host byte order */ #ifdef __WIN32__ if (send(netlsp[0], buff, len, 0) < 0) { #else if (write(netlsp[0], buff, len) < 0) { #endif printf("netlink_send_addr() write error: %s", strerror(errno)); return(-1); } return(0); } int sendIpAddrTable(PMIB_IPADDRTABLE pTable) { char buff[1024]; int len, total_len = 0, status, i; struct nlmsghdr *msg; struct ifaddrmsg *ifa; struct rtattr *rta; __u32 *p_addr; if (!pTable) { return(-1); } memset(buff, 0, sizeof(buff)); status = sizeof(buff); len = NLMSG_LENGTH( sizeof(struct ifaddrmsg) + sizeof(struct rtattr) + sizeof(__u32)); msg = (struct nlmsghdr *) buff; /* due to timing, 1.0.0.1 is not in Window's IP table yet, * but is needed by hipd for the ACQUIRE, so here we add * it manually */ msg->nlmsg_len = NLMSG_ALIGN(len); total_len += len; msg->nlmsg_type = NLMSG_NOOP; msg->nlmsg_flags = 0; msg->nlmsg_seq = 0; msg->nlmsg_pid = 0; ifa = (struct ifaddrmsg*) NLMSG_DATA(msg); ifa->ifa_family = AF_INET; ifa->ifa_prefixlen = 32; ifa->ifa_flags = IFA_F_PERMANENT; ifa->ifa_scope = IFA_LOCAL; ifa->ifa_index = 65542; rta = IFA_RTA(ifa); rta->rta_len = RTA_LENGTH(sizeof(__u32)); rta->rta_type = IFA_LOCAL; p_addr = (__u32*)(rta + 1); *p_addr = g_tap_lsi; msg = NLMSG_NEXT(msg, status); /* step through IP address table and add to netlink dump message */ for (i = 0; i < (int)pTable->dwNumEntries; i++) { /* omit 0.0.0.0; (1.0.0.1 is needed for ACQUIRE mechanism) */ if (pTable->table[i].dwAddr == 0) { continue; } msg->nlmsg_len = NLMSG_ALIGN(len); total_len += len; msg->nlmsg_type = NLMSG_NOOP; msg->nlmsg_flags = 0; msg->nlmsg_seq = 0; msg->nlmsg_pid = 0; /* interface address message */ ifa = (struct ifaddrmsg*) NLMSG_DATA(msg); ifa->ifa_family = AF_INET; ifa->ifa_prefixlen = 32; ifa->ifa_flags = IFA_F_PERMANENT; ifa->ifa_scope = IFA_LOCAL; ifa->ifa_index = pTable->table[i].dwIndex; /* route attributes */ rta = IFA_RTA(ifa); rta->rta_len = RTA_LENGTH(sizeof(__u32)); rta->rta_type = IFA_LOCAL; p_addr = (__u32*)(rta + 1); *p_addr = pTable->table[i].dwAddr; msg = NLMSG_NEXT(msg, status); } /* finish with a done message */ msg->nlmsg_len = NLMSG_LENGTH(0); msg->nlmsg_type = NLMSG_DONE; msg->nlmsg_flags = 0; msg->nlmsg_seq = 0; msg->nlmsg_pid = 0; total_len += msg->nlmsg_len; #ifdef __WIN32__ send(netlsp[0], buff, total_len, 0); #else write(netlsp[0], buff, total_len); #endif return(total_len); }
/* Add/Delete IP rule to/from a specific IP/network */ static int netlink_rule(ip_rule_t *iprule, int cmd) { int status = 1; struct { struct nlmsghdr n; struct fib_rule_hdr frh; char buf[1024]; } req; memset(&req, 0, sizeof (req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; if (cmd != IPRULE_DEL) { req.n.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; req.n.nlmsg_type = RTM_NEWRULE; req.frh.action = FR_ACT_UNSPEC; } else { req.frh.action = FR_ACT_UNSPEC; req.n.nlmsg_type = RTM_DELRULE; } req.frh.table = RT_TABLE_UNSPEC; req.frh.flags = 0; req.frh.tos = iprule->tos; // Hex value - 0xnn <= 255, or name from rt_dsfield req.frh.family = iprule->family; if (iprule->action == FR_ACT_TO_TBL #if HAVE_DECL_FRA_L3MDEV && !iprule->l3mdev #endif ) { if (iprule->table < 256) // "Table" or "lookup" req.frh.table = iprule->table ? iprule->table & 0xff : RT_TABLE_MAIN; else { req.frh.table = RT_TABLE_UNSPEC; addattr32(&req.n, sizeof(req), FRA_TABLE, iprule->table); } } if (iprule->invert) req.frh.flags |= FIB_RULE_INVERT; // "not" /* Set rule entry */ if (iprule->from_addr) { // can be "default"/"any"/"all" - and to addr => bytelen == bitlen == 0 add_addr2req(&req.n, sizeof(req), FRA_SRC, iprule->from_addr); req.frh.src_len = iprule->from_addr->ifa.ifa_prefixlen; } if (iprule->to_addr) { add_addr2req(&req.n, sizeof(req), FRA_DST, iprule->to_addr); req.frh.dst_len = iprule->to_addr->ifa.ifa_prefixlen; } if (iprule->mask & IPRULE_BIT_PRIORITY) // "priority/order/preference" addattr32(&req.n, sizeof(req), FRA_PRIORITY, iprule->priority); if (iprule->mask & IPRULE_BIT_FWMARK) // "fwmark" addattr32(&req.n, sizeof(req), FRA_FWMARK, iprule->fwmark); if (iprule->mask & IPRULE_BIT_FWMASK) // "fwmark number followed by /nn" addattr32(&req.n, sizeof(req), FRA_FWMASK, iprule->fwmask); if (iprule->realms) // "realms u16[/u16] using rt_realms. after / is 16 msb (src), pre slash is 16 lsb (dest)" addattr32(&req.n, sizeof(req), FRA_FLOW, iprule->realms); #if HAVE_DECL_FRA_SUPPRESS_PREFIXLEN if (iprule->suppress_prefix_len != -1) // "suppress_prefixlength" - only valid if table != 0 addattr32(&req.n, sizeof(req), FRA_SUPPRESS_PREFIXLEN, iprule->suppress_prefix_len); #endif #if HAVE_DECL_FRA_SUPPRESS_IFGROUP if (iprule->mask & IPRULE_BIT_SUP_GROUP) // "suppress_ifgroup" or "sup_group" int32 - only valid if table !=0 addattr32(&req.n, sizeof(req), FRA_SUPPRESS_IFGROUP, iprule->suppress_group); #endif if (iprule->iif) // "dev/iif" addattr_l(&req.n, sizeof(req), FRA_IFNAME, iprule->iif, strlen(iprule->iif->ifname)+1); #if HAVE_DECL_FRA_OIFNAME if (iprule->oif) // "oif" addattr_l(&req.n, sizeof(req), FRA_OIFNAME, iprule->oif, strlen(iprule->oif->ifname)+1); #endif #if HAVE_DECL_FRA_TUN_ID if (iprule->tunnel_id) addattr64(&req.n, sizeof(req), FRA_TUN_ID, htobe64(iprule->tunnel_id)); #endif #if HAVE_DECL_FRA_UID_RANGE if (iprule->mask & IPRULE_BIT_UID_RANGE) addattr_l(&req.n, sizeof(req), FRA_UID_RANGE, &iprule->uid_range, sizeof(iprule->uid_range)); #endif #if HAVE_DECL_FRA_L3MDEV if (iprule->l3mdev) addattr8(&req.n, sizeof(req), FRA_L3MDEV, 1); #endif #if HAVE_DECL_FRA_PROTOCOL if (iprule->mask & IPRULE_BIT_PROTOCOL) addattr8(&req.n, sizeof(req), FRA_PROTOCOL, iprule->protocol); #endif #if HAVE_DECL_FRA_IP_PROTO if (iprule->mask & IPRULE_BIT_IP_PROTO) addattr8(&req.n, sizeof(req), FRA_IP_PROTO, iprule->ip_proto); #endif #if HAVE_DECL_FRA_SPORT_RANGE if (iprule->mask & IPRULE_BIT_SPORT_RANGE) addattr_l(&req.n, sizeof(req), FRA_SPORT_RANGE, &iprule->src_port, sizeof(iprule->src_port)); #endif #if HAVE_DECL_FRA_DPORT_RANGE if (iprule->mask & IPRULE_BIT_DPORT_RANGE) addattr_l(&req.n, sizeof(req), FRA_DPORT_RANGE, &iprule->dst_port, sizeof(iprule->dst_port)); #endif if (iprule->action == FR_ACT_GOTO) { // "goto" addattr32(&req.n, sizeof(req), FRA_GOTO, iprule->goto_target); req.frh.action = FR_ACT_GOTO; } req.frh.action = iprule->action; if (netlink_talk(&nl_cmd, &req.n) < 0) status = -1; return status; }
static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE *) arg; struct genlmsghdr *ghdr; struct rtattr *attrs[TCP_METRICS_ATTR_MAX + 1], *a; int len = n->nlmsg_len; char abuf[256]; inet_prefix addr; int family, i, atype; if (n->nlmsg_type != genl_family) return -1; len -= NLMSG_LENGTH(GENL_HDRLEN); if (len < 0) return -1; ghdr = NLMSG_DATA(n); if (ghdr->cmd != TCP_METRICS_CMD_GET) return 0; parse_rtattr(attrs, TCP_METRICS_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, len); a = attrs[TCP_METRICS_ATTR_ADDR_IPV4]; if (a) { if (f.addr.family && f.addr.family != AF_INET) return 0; memcpy(&addr.data, RTA_DATA(a), 4); addr.bytelen = 4; family = AF_INET; atype = TCP_METRICS_ATTR_ADDR_IPV4; } else { a = attrs[TCP_METRICS_ATTR_ADDR_IPV6]; if (a) { if (f.addr.family && f.addr.family != AF_INET6) return 0; memcpy(&addr.data, RTA_DATA(a), 16); addr.bytelen = 16; family = AF_INET6; atype = TCP_METRICS_ATTR_ADDR_IPV6; } else return 0; } if (f.addr.family && f.addr.bitlen >= 0 && inet_addr_match(&addr, &f.addr, f.addr.bitlen)) return 0; if (f.flushb) { struct nlmsghdr *fn; TCPM_REQUEST(req2, 128, TCP_METRICS_CMD_DEL, NLM_F_REQUEST); addattr_l(&req2.n, sizeof(req2), atype, &addr.data, addr.bytelen); if (NLMSG_ALIGN(f.flushp) + req2.n.nlmsg_len > f.flushe) { if (flush_update()) return -1; } fn = (struct nlmsghdr *) (f.flushb + NLMSG_ALIGN(f.flushp)); memcpy(fn, &req2.n, req2.n.nlmsg_len); fn->nlmsg_seq = ++grth.seq; f.flushp = (((char *) fn) + req2.n.nlmsg_len) - f.flushb; f.flushed++; if (show_stats < 2) return 0; } if (f.cmd & (CMD_DEL | CMD_FLUSH)) fprintf(fp, "Deleted "); fprintf(fp, "%s", format_host(family, RTA_PAYLOAD(a), &addr.data, abuf, sizeof(abuf))); a = attrs[TCP_METRICS_ATTR_AGE]; if (a) { __u64 val = rta_getattr_u64(a); fprintf(fp, " age %llu.%03llusec", val / 1000, val % 1000); } a = attrs[TCP_METRICS_ATTR_TW_TS_STAMP]; if (a) { __s32 val = (__s32) rta_getattr_u32(a); __u32 tsval; a = attrs[TCP_METRICS_ATTR_TW_TSVAL]; tsval = a ? rta_getattr_u32(a) : 0; fprintf(fp, " tw_ts %u/%dsec ago", tsval, val); } a = attrs[TCP_METRICS_ATTR_VALS]; if (a) { struct rtattr *m[TCP_METRIC_MAX + 1 + 1]; parse_rtattr_nested(m, TCP_METRIC_MAX + 1, a); for (i = 0; i < TCP_METRIC_MAX + 1; i++) { __u32 val; a = m[i + 1]; if (!a) continue; if (metric_name[i]) fprintf(fp, " %s ", metric_name[i]); else fprintf(fp, " metric_%d ", i); val = rta_getattr_u32(a); switch (i) { case TCP_METRIC_RTT: fprintf(fp, "%lluus", (val * 1000ULL) >> 3); break; case TCP_METRIC_RTTVAR: fprintf(fp, "%lluus", (val * 1000ULL) >> 2); break; case TCP_METRIC_SSTHRESH: case TCP_METRIC_CWND: case TCP_METRIC_REORDERING: default: fprintf(fp, "%u", val); break; } } } a = attrs[TCP_METRICS_ATTR_FOPEN_MSS]; if (a) fprintf(fp, " fo_mss %u", rta_getattr_u16(a)); a = attrs[TCP_METRICS_ATTR_FOPEN_SYN_DROPS]; if (a) { __u16 syn_loss = rta_getattr_u16(a); __u64 ts; a = attrs[TCP_METRICS_ATTR_FOPEN_SYN_DROP_TS]; ts = a ? rta_getattr_u64(a) : 0; fprintf(fp, " fo_syn_drops %u/%llu.%03llusec ago", syn_loss, ts / 1000, ts % 1000); } a = attrs[TCP_METRICS_ATTR_FOPEN_COOKIE]; if (a) { char cookie[32 + 1]; unsigned char *ptr = RTA_DATA(a); int i, max = RTA_PAYLOAD(a); if (max > 16) max = 16; cookie[0] = 0; for (i = 0; i < max; i++) sprintf(cookie + i + i, "%02x", ptr[i]); fprintf(fp, " fo_cookie %s", cookie); } fprintf(fp, "\n"); fflush(fp); return 0; }
int rtnl_dump_filter(struct rtnl_handle *rth, rtnl_filter_t filter, void *arg1, rtnl_filter_t junk, void *arg2) { char buf[16384]; struct sockaddr_nl nladdr; struct iovec iov = { buf, sizeof(buf) }; while (1) { int status; struct nlmsghdr *h; struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 }; status = recvmsg(rth->fd, &msg, 0); if (status < 0) { if (errno == EINTR) continue; perror("OVERRUN"); continue; } if (status == 0) { fprintf(stderr, "EOF on netlink\n"); return -1; } if (msg.msg_namelen != sizeof(nladdr)) { fprintf(stderr, "sender address length == %d\n", msg.msg_namelen); exit(1); } h = (struct nlmsghdr*)buf; while (NLMSG_OK(h, status)) { int err; if (nladdr.nl_pid != 0 || h->nlmsg_pid != rth->local.nl_pid || h->nlmsg_seq != rth->dump) { if (junk) { err = junk(&nladdr, h, arg2); if (err < 0) return err; } goto skip_it; } if (h->nlmsg_type == NLMSG_DONE) return 0; if (h->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { fprintf(stderr, "ERROR truncated\n"); } else { errno = -err->error; perror("RTNETLINK answers"); } return -1; } err = filter(&nladdr, h, arg1); if (err < 0) return err; skip_it: h = NLMSG_NEXT(h, status); } if (msg.msg_flags & MSG_TRUNC) { fprintf(stderr, "Message truncated\n"); continue; } if (status) { fprintf(stderr, "!!!Remnant of size %d\n", status); exit(1); } } }
/* * scamper_rtsock_getifindex * * figure out the outgoing interface id / route using linux netlink * * this works on Linux systems with netlink compiled into the kernel. * i think netlink comes compiled into the kernel with most distributions * these days. * * the man pages netlink(3), netlink(7), rtnetlink(3), and rtnetlink(7) * give an overview of the functions and structures used in here, but the * documentation in those man pages is pretty crap. * you'd be better off studying netlink.h and rtnetlink.h */ static int scamper_rtsock_getifindex(int fd, scamper_addr_t *dst) { struct nlmsghdr *nlmsg; struct rtmsg *rtmsg; struct rtattr *rta; int error; int dst_len; uint8_t buf[1024]; int af; if(SCAMPER_ADDR_TYPE_IS_IPV4(dst)) { dst_len = 4; af = AF_INET; } else if(SCAMPER_ADDR_TYPE_IS_IPV6(dst)) { dst_len = 16; af = AF_INET6; } else { return -1; } /* * fill out a route request. * we use the standard netlink header, with a route msg subheader * to query for the outgoing interface. * the message includes one attribute - the destination address * we are querying the route for. */ memset(buf, 0, sizeof(buf)); nlmsg = (struct nlmsghdr *)buf; nlmsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); nlmsg->nlmsg_type = RTM_GETROUTE; nlmsg->nlmsg_flags = NLM_F_REQUEST; nlmsg->nlmsg_seq = seq; nlmsg->nlmsg_pid = pid; /* netlink wants the bit length of each address */ rtmsg = NLMSG_DATA(nlmsg); rtmsg->rtm_family = af; rtmsg->rtm_flags = 0; rtmsg->rtm_dst_len = dst_len * 8; rta = (struct rtattr *)(buf + NLMSG_ALIGN(nlmsg->nlmsg_len)); rta->rta_type = RTA_DST; rta->rta_len = RTA_LENGTH(dst_len); nlmsg->nlmsg_len += RTA_LENGTH(dst_len); memcpy(RTA_DATA(rta), dst->addr, dst_len); /* send the request */ if((error = send(fd, buf, nlmsg->nlmsg_len, 0)) != nlmsg->nlmsg_len) { printerror(errno, strerror, __func__, "could not send"); return -1; } return 0; }
static int communicate_kernel(struct ip_classify_msg *request,int type) { int sock; int recv_len; int respond_size; void *respond; struct msghdr msg; struct iovec iov; struct sockaddr_nl remote; struct sockaddr_nl local; struct nlmsghdr * nlhdr; struct nlmsghdr * rnlhdr=NULL; socklen_t remote_addr_len; int res, ret = -1; sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_IP_CLASSIFY); if(sock < 0) { DEBUGP("create socket error\n"); return ret; } memset(&local, 0, sizeof(struct sockaddr_nl)); local.nl_family = AF_NETLINK; local.nl_pid = getpid(); local.nl_groups = 0; if(bind(sock, (struct sockaddr*)&local, sizeof(struct sockaddr_nl)) != 0) { DEBUGP("bind socket error\n"); goto exit; } memset(&remote, 0, sizeof(struct sockaddr_nl)); remote.nl_family = AF_NETLINK; remote.nl_pid = 0; remote.nl_groups = 0; memset(&msg, 0, sizeof(struct msghdr)); nlhdr = (struct nlmsghdr *)malloc(NLMSG_SPACE(sizeof(struct ip_classify_msg))); memcpy(NLMSG_DATA(nlhdr), (char *)request, sizeof(struct ip_classify_msg)); nlhdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ip_classify_msg)); nlhdr->nlmsg_pid = getpid(); nlhdr->nlmsg_flags = NLM_F_REQUEST; nlhdr->nlmsg_type = type; iov.iov_base = (void *)nlhdr; iov.iov_len = nlhdr->nlmsg_len; msg.msg_name = (void *)&remote; msg.msg_namelen = sizeof(remote); msg.msg_iov = &iov; msg.msg_iovlen = 1; res = sendmsg(sock, &msg, 0); if (res == -1) { DEBUGP("sendmsg error\n"); goto exit; } remote_addr_len = sizeof(struct sockaddr_nl); respond_size = sizeof(struct ip_classify_respond_info); respond = malloc(respond_size); memset(respond, 0, respond_size); recv_len = recvfrom(sock, respond, respond_size, 0, (struct sockaddr*)&remote, &remote_addr_len); if(recv_len == -1) { DEBUGP("recvmsg error\n"); goto exit; } rnlhdr = (struct nlmsghdr *)respond; switch(rnlhdr->nlmsg_type) { case IP_CLASSIFY_DONE: ret = 0; break; case IP_CLASSIFY_ERROR: DEBUGP("ip-classify command error\n"); break; case IP_CLASSIFY_MEMERR: DEBUGP("ip-classify malloc memery error\n"); break; default: DEBUGP("ip-classify error, error type : %u\n", rnlhdr->nlmsg_type); break; } exit: close(sock); if(respond) { free(respond); } if(nlhdr) { free(nlhdr); } return ret; }
static void rtsock_parsemsg(uint8_t *buf, size_t len) { struct nlmsghdr *nlmsg; struct nlmsgerr *nlerr; struct rtmsg *rtmsg; struct rtattr *rta; void *gwa = NULL; int ifindex = -1; scamper_addr_t *gw = NULL; rtsock_pair_t *pair = NULL; scamper_route_t *route = NULL; if(len < sizeof(struct nlmsghdr)) { scamper_debug(__func__, "len %d != %d", len, sizeof(struct nlmsghdr)); return; } nlmsg = (struct nlmsghdr *)buf; /* if the message isn't addressed to this pid, drop it */ if(nlmsg->nlmsg_pid != pid) return; if((pair = rtsock_pair_get(nlmsg->nlmsg_seq)) == NULL) return; route = pair->route; rtsock_pair_free(pair); if(nlmsg->nlmsg_type == RTM_NEWROUTE) { rtmsg = NLMSG_DATA(nlmsg); /* this is the payload length of the response packet */ len = nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)); /* hunt through the payload for the RTA_OIF entry */ rta = RTM_RTA(rtmsg); while(RTA_OK(rta, len)) { switch(rta->rta_type) { case RTA_OIF: ifindex = *(unsigned *)RTA_DATA(rta); break; case RTA_GATEWAY: gwa = RTA_DATA(rta); break; } rta = RTA_NEXT(rta, len); } if(gwa != NULL) { if(rtmsg->rtm_family == AF_INET) gw = scamper_addrcache_get_ipv4(addrcache, gwa); else if(rtmsg->rtm_family == AF_INET6) gw = scamper_addrcache_get_ipv6(addrcache, gwa); else route->error = EINVAL; } } else if(nlmsg->nlmsg_type == NLMSG_ERROR) { nlerr = NLMSG_DATA(nlmsg); route->error = nlerr->error; } else goto skip; route->gw = gw; route->ifindex = ifindex; route->cb(route); return; skip: if(route != NULL) scamper_route_free(route); return; }
static int ctrl_list(int cmd, int argc, char **argv) { struct rtnl_handle rth; struct nlmsghdr *nlh; struct genlmsghdr *ghdr; int ret = -1; char d[GENL_NAMSIZ]; struct { struct nlmsghdr n; char buf[4096]; } req; memset(&req, 0, sizeof(req)); nlh = &req.n; nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; nlh->nlmsg_type = GENL_ID_CTRL; ghdr = NLMSG_DATA(&req.n); ghdr->cmd = CTRL_CMD_GETFAMILY; if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) { fprintf(stderr, "Cannot open generic netlink socket\n"); exit(1); } if (cmd == CTRL_CMD_GETFAMILY) { if (argc != 2) { fprintf(stderr, "Wrong number of params\n"); return -1; } if (matches(*argv, "name") == 0) { NEXT_ARG(); strncpy(d, *argv, sizeof (d) - 1); addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME, d, strlen(d) + 1); } else if (matches(*argv, "id") == 0) { __u16 id; NEXT_ARG(); if (get_u16(&id, *argv, 0)) { fprintf(stderr, "Illegal \"id\"\n"); goto ctrl_done; } addattr_l(nlh, 128, CTRL_ATTR_FAMILY_ID, &id, 2); } else { fprintf(stderr, "Wrong params\n"); goto ctrl_done; } if (rtnl_talk(&rth, nlh, nlh, sizeof(req)) < 0) { fprintf(stderr, "Error talking to the kernel\n"); goto ctrl_done; } if (print_ctrl2(NULL, nlh, (void *) stdout) < 0) { fprintf(stderr, "Dump terminated\n"); goto ctrl_done; } } if (cmd == CTRL_CMD_UNSPEC) { nlh->nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; nlh->nlmsg_seq = rth.dump = ++rth.seq; if (rtnl_send(&rth, nlh, nlh->nlmsg_len) < 0) { perror("Failed to send dump request\n"); goto ctrl_done; } rtnl_dump_filter(&rth, print_ctrl2, stdout); } ret = 0; ctrl_done: rtnl_close(&rth); return ret; }
std::vector<ip_route> enum_routes(io_service& ios, error_code& ec) { std::vector<ip_route> ret; TORRENT_UNUSED(ios); #ifdef TORRENT_BUILD_SIMULATOR TORRENT_UNUSED(ec); ip_route r; r.destination = address_v4(); r.netmask = address_v4::from_string("255.255.255.0"); address_v4::bytes_type b = ios.get_ip().to_v4().to_bytes(); b[3] = 1; r.gateway = address_v4(b); strcpy(r.name, "eth0"); r.mtu = ios.sim().config().path_mtu(ios.get_ip(), ios.get_ip()); ret.push_back(r); #elif TORRENT_USE_SYSCTL /* struct rt_msg { rt_msghdr m_rtm; char buf[512]; }; rt_msg m; int len = sizeof(rt_msg); bzero(&m, len); m.m_rtm.rtm_type = RTM_GET; m.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY; m.m_rtm.rtm_version = RTM_VERSION; m.m_rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; m.m_rtm.rtm_seq = 0; m.m_rtm.rtm_msglen = len; int s = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC); if (s == -1) { ec = error_code(errno, boost::asio::error::system_category); return std::vector<ip_route>(); } int n = write(s, &m, len); if (n == -1) { ec = error_code(errno, boost::asio::error::system_category); close(s); return std::vector<ip_route>(); } else if (n != len) { ec = boost::asio::error::operation_not_supported; close(s); return std::vector<ip_route>(); } bzero(&m, len); n = read(s, &m, len); if (n == -1) { ec = error_code(errno, boost::asio::error::system_category); close(s); return std::vector<ip_route>(); } for (rt_msghdr* ptr = &m.m_rtm; (char*)ptr < ((char*)&m.m_rtm) + n; ptr = (rt_msghdr*)(((char*)ptr) + ptr->rtm_msglen)) { std::cout << " rtm_msglen: " << ptr->rtm_msglen << std::endl; std::cout << " rtm_type: " << ptr->rtm_type << std::endl; if (ptr->rtm_errno) { ec = error_code(ptr->rtm_errno, boost::asio::error::system_category); return std::vector<ip_route>(); } if (m.m_rtm.rtm_flags & RTF_UP == 0 || m.m_rtm.rtm_flags & RTF_GATEWAY == 0) { ec = boost::asio::error::operation_not_supported; return address_v4::any(); } if (ptr->rtm_addrs & RTA_DST == 0 || ptr->rtm_addrs & RTA_GATEWAY == 0 || ptr->rtm_addrs & RTA_NETMASK == 0) { ec = boost::asio::error::operation_not_supported; return std::vector<ip_route>(); } if (ptr->rtm_msglen > len - ((char*)ptr - ((char*)&m.m_rtm))) { ec = boost::asio::error::operation_not_supported; return std::vector<ip_route>(); } int min_len = sizeof(rt_msghdr) + 2 * sizeof(sockaddr_in); if (m.m_rtm.rtm_msglen < min_len) { ec = boost::asio::error::operation_not_supported; return std::vector<ip_route>(); } ip_route r; // destination char* p = m.buf; sockaddr_in* sin = (sockaddr_in*)p; r.destination = sockaddr_to_address((sockaddr*)p); // gateway p += sin->sin_len; sin = (sockaddr_in*)p; r.gateway = sockaddr_to_address((sockaddr*)p); // netmask p += sin->sin_len; sin = (sockaddr_in*)p; r.netmask = sockaddr_to_address((sockaddr*)p); ret.push_back(r); } close(s); */ int mib[6] = { CTL_NET, PF_ROUTE, 0, AF_UNSPEC, NET_RT_DUMP, 0}; size_t needed = 0; #ifdef TORRENT_OS2 if (__libsocket_sysctl(mib, 6, 0, &needed, 0, 0) < 0) #else if (sysctl(mib, 6, 0, &needed, 0, 0) < 0) #endif { ec = error_code(errno, boost::asio::error::system_category); return std::vector<ip_route>(); } if (needed <= 0) { return std::vector<ip_route>(); } boost::scoped_array<char> buf(new (std::nothrow) char[needed]); if (buf.get() == 0) { ec = boost::asio::error::no_memory; return std::vector<ip_route>(); } #ifdef TORRENT_OS2 if (__libsocket_sysctl(mib, 6, buf.get(), &needed, 0, 0) < 0) #else if (sysctl(mib, 6, buf.get(), &needed, 0, 0) < 0) #endif { ec = error_code(errno, boost::asio::error::system_category); return std::vector<ip_route>(); } char* end = buf.get() + needed; int s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { ec = error_code(errno, boost::asio::error::system_category); return std::vector<ip_route>(); } rt_msghdr* rtm; for (char* next = buf.get(); next < end; next += rtm->rtm_msglen) { rtm = reinterpret_cast<rt_msghdr*>(next); if (rtm->rtm_version != RTM_VERSION) continue; ip_route r; if (parse_route(s, rtm, &r)) ret.push_back(r); } close(s); #elif TORRENT_USE_GETIPFORWARDTABLE /* move this to enum_net_interfaces // Load Iphlpapi library HMODULE iphlp = LoadLibraryA("Iphlpapi.dll"); if (!iphlp) { ec = boost::asio::error::operation_not_supported; return std::vector<ip_route>(); } // Get GetAdaptersInfo() pointer typedef DWORD (WINAPI *GetAdaptersInfo_t)(PIP_ADAPTER_INFO, PULONG); GetAdaptersInfo_t GetAdaptersInfo = (GetAdaptersInfo_t)GetProcAddress(iphlp, "GetAdaptersInfo"); if (!GetAdaptersInfo) { FreeLibrary(iphlp); ec = boost::asio::error::operation_not_supported; return std::vector<ip_route>(); } PIP_ADAPTER_INFO adapter_info = 0; ULONG out_buf_size = 0; if (GetAdaptersInfo(adapter_info, &out_buf_size) != ERROR_BUFFER_OVERFLOW) { FreeLibrary(iphlp); ec = boost::asio::error::operation_not_supported; return std::vector<ip_route>(); } adapter_info = (IP_ADAPTER_INFO*)malloc(out_buf_size); if (!adapter_info) { FreeLibrary(iphlp); ec = boost::asio::error::no_memory; return std::vector<ip_route>(); } if (GetAdaptersInfo(adapter_info, &out_buf_size) == NO_ERROR) { for (PIP_ADAPTER_INFO adapter = adapter_info; adapter != 0; adapter = adapter->Next) { ip_route r; r.destination = address::from_string(adapter->IpAddressList.IpAddress.String, ec); r.gateway = address::from_string(adapter->GatewayList.IpAddress.String, ec); r.netmask = address::from_string(adapter->IpAddressList.IpMask.String, ec); strncpy(r.name, adapter->AdapterName, sizeof(r.name)); if (ec) { ec = error_code(); continue; } ret.push_back(r); } } // Free memory free(adapter_info); FreeLibrary(iphlp); */ // Load Iphlpapi library HMODULE iphlp = LoadLibraryA("Iphlpapi.dll"); if (!iphlp) { ec = boost::asio::error::operation_not_supported; return std::vector<ip_route>(); } typedef DWORD (WINAPI *GetIfEntry_t)(PMIB_IFROW pIfRow); GetIfEntry_t GetIfEntry = (GetIfEntry_t)GetProcAddress(iphlp, "GetIfEntry"); if (!GetIfEntry) { ec = boost::asio::error::operation_not_supported; return std::vector<ip_route>(); } #if _WIN32_WINNT >= 0x0600 typedef DWORD (WINAPI *GetIpForwardTable2_t)( ADDRESS_FAMILY, PMIB_IPFORWARD_TABLE2*); typedef void (WINAPI *FreeMibTable_t)(PVOID Memory); GetIpForwardTable2_t GetIpForwardTable2 = (GetIpForwardTable2_t)GetProcAddress( iphlp, "GetIpForwardTable2"); FreeMibTable_t FreeMibTable = (FreeMibTable_t)GetProcAddress( iphlp, "FreeMibTable"); if (GetIpForwardTable2 && FreeMibTable) { MIB_IPFORWARD_TABLE2* routes = NULL; int res = GetIpForwardTable2(AF_UNSPEC, &routes); if (res == NO_ERROR) { for (int i = 0; i < routes->NumEntries; ++i) { ip_route r; r.gateway = sockaddr_to_address((const sockaddr*)&routes->Table[i].NextHop); r.destination = sockaddr_to_address( (const sockaddr*)&routes->Table[i].DestinationPrefix.Prefix); r.netmask = build_netmask(routes->Table[i].SitePrefixLength , routes->Table[i].DestinationPrefix.Prefix.si_family); MIB_IFROW ifentry; ifentry.dwIndex = routes->Table[i].InterfaceIndex; if (GetIfEntry(&ifentry) == NO_ERROR) { wcstombs(r.name, ifentry.wszName, sizeof(r.name)); r.mtu = ifentry.dwMtu; ret.push_back(r); } } } if (routes) FreeMibTable(routes); FreeLibrary(iphlp); return ret; } #endif // Get GetIpForwardTable() pointer typedef DWORD (WINAPI *GetIpForwardTable_t)(PMIB_IPFORWARDTABLE pIpForwardTable,PULONG pdwSize,BOOL bOrder); GetIpForwardTable_t GetIpForwardTable = (GetIpForwardTable_t)GetProcAddress( iphlp, "GetIpForwardTable"); if (!GetIpForwardTable) { FreeLibrary(iphlp); ec = boost::asio::error::operation_not_supported; return std::vector<ip_route>(); } MIB_IPFORWARDTABLE* routes = NULL; ULONG out_buf_size = 0; if (GetIpForwardTable(routes, &out_buf_size, FALSE) != ERROR_INSUFFICIENT_BUFFER) { FreeLibrary(iphlp); ec = boost::asio::error::operation_not_supported; return std::vector<ip_route>(); } routes = (MIB_IPFORWARDTABLE*)malloc(out_buf_size); if (!routes) { FreeLibrary(iphlp); ec = boost::asio::error::no_memory; return std::vector<ip_route>(); } if (GetIpForwardTable(routes, &out_buf_size, FALSE) == NO_ERROR) { for (int i = 0; i < routes->dwNumEntries; ++i) { ip_route r; r.destination = inaddr_to_address((in_addr const*)&routes->table[i].dwForwardDest); r.netmask = inaddr_to_address((in_addr const*)&routes->table[i].dwForwardMask); r.gateway = inaddr_to_address((in_addr const*)&routes->table[i].dwForwardNextHop); MIB_IFROW ifentry; ifentry.dwIndex = routes->table[i].dwForwardIfIndex; if (GetIfEntry(&ifentry) == NO_ERROR) { wcstombs(r.name, ifentry.wszName, sizeof(r.name)); r.name[sizeof(r.name)-1] = 0; r.mtu = ifentry.dwMtu; ret.push_back(r); } } } // Free memory free(routes); FreeLibrary(iphlp); #elif TORRENT_USE_NETLINK enum { BUFSIZE = 8192 }; int sock = socket(PF_ROUTE, SOCK_DGRAM, NETLINK_ROUTE); if (sock < 0) { ec = error_code(errno, boost::asio::error::system_category); return std::vector<ip_route>(); } int seq = 0; char msg[BUFSIZE]; memset(msg, 0, BUFSIZE); nlmsghdr* nl_msg = (nlmsghdr*)msg; nl_msg->nlmsg_len = NLMSG_LENGTH(sizeof(rtmsg)); nl_msg->nlmsg_type = RTM_GETROUTE; nl_msg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; nl_msg->nlmsg_seq = seq++; nl_msg->nlmsg_pid = getpid(); if (send(sock, nl_msg, nl_msg->nlmsg_len, 0) < 0) { ec = error_code(errno, boost::asio::error::system_category); close(sock); return std::vector<ip_route>(); } int len = read_nl_sock(sock, msg, BUFSIZE, seq, getpid()); if (len < 0) { ec = error_code(errno, boost::asio::error::system_category); close(sock); return std::vector<ip_route>(); } int s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { ec = error_code(errno, boost::asio::error::system_category); return std::vector<ip_route>(); } for (; NLMSG_OK(nl_msg, len); nl_msg = NLMSG_NEXT(nl_msg, len)) { ip_route r; if (parse_route(s, nl_msg, &r)) ret.push_back(r); } close(s); close(sock); #endif return ret; }
int print_qdisc(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { FILE *fp = (FILE*)arg; struct tcmsg *t = NLMSG_DATA(n); int len = n->nlmsg_len; struct rtattr * tb[TCA_MAX+1]; struct qdisc_util *q; char abuf[256]; if (n->nlmsg_type != RTM_NEWQDISC && n->nlmsg_type != RTM_DELQDISC) { fprintf(stderr, "Not a qdisc\n"); return 0; } len -= NLMSG_LENGTH(sizeof(*t)); if (len < 0) { fprintf(stderr, "Wrong len %d\n", len); return -1; } if (filter_ifindex && filter_ifindex != t->tcm_ifindex) return 0; memset(tb, 0, sizeof(tb)); parse_rtattr(tb, TCA_MAX, TCA_RTA(t), len); if (tb[TCA_KIND] == NULL) { fprintf(stderr, "print_qdisc: NULL kind\n"); return -1; } if (n->nlmsg_type == RTM_DELQDISC) fprintf(fp, "deleted "); fprintf(fp, "qdisc %s %x: ", rta_getattr_str(tb[TCA_KIND]), t->tcm_handle>>16); if (filter_ifindex == 0) fprintf(fp, "dev %s ", ll_index_to_name(t->tcm_ifindex)); if (t->tcm_parent == TC_H_ROOT) fprintf(fp, "root "); else if (t->tcm_parent) { print_tc_classid(abuf, sizeof(abuf), t->tcm_parent); fprintf(fp, "parent %s ", abuf); } if (t->tcm_info != 1) { fprintf(fp, "refcnt %d ", t->tcm_info); } /* pfifo_fast is generic enough to warrant the hardcoding --JHS */ if (0 == strcmp("pfifo_fast", RTA_DATA(tb[TCA_KIND]))) q = get_qdisc_kind("prio"); else q = get_qdisc_kind(RTA_DATA(tb[TCA_KIND])); if (tb[TCA_OPTIONS]) { if (q) q->print_qopt(q, fp, tb[TCA_OPTIONS]); else fprintf(fp, "[cannot parse qdisc parameters]"); } fprintf(fp, "\n"); if (show_details && tb[TCA_STAB]) { print_size_table(fp, " ", tb[TCA_STAB]); fprintf(fp, "\n"); } if (show_stats) { struct rtattr *xstats = NULL; if (tb[TCA_STATS] || tb[TCA_STATS2] || tb[TCA_XSTATS]) { print_tcstats_attr(fp, tb, " ", &xstats); fprintf(fp, "\n"); } if (q && xstats && q->print_xstats) { q->print_xstats(q, fp, xstats); fprintf(fp, "\n"); } } fflush(fp); return 0; }
static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) { int len; char *dev = NULL; char *name = NULL; char *link = NULL; char *type = NULL; int group; struct link_util *lu = NULL; struct iplink_req req; int ret; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); req.n.nlmsg_flags = NLM_F_REQUEST|flags; req.n.nlmsg_type = cmd; req.i.ifi_family = preferred_family; ret = iplink_parse(argc, argv, &req, &name, &type, &link, &dev, &group); if (ret < 0) return ret; argc -= ret; argv += ret; if (group != -1) { if (dev) addattr_l(&req.n, sizeof(req), IFLA_GROUP, &group, sizeof(group)); else { if (argc) { fprintf(stderr, "Garbage instead of arguments " "\"%s ...\". Try \"ip link " "help\".\n", *argv); return -1; } if (flags & NLM_F_CREATE) { fprintf(stderr, "group cannot be used when " "creating devices.\n"); return -1; } req.i.ifi_index = 0; addattr32(&req.n, sizeof(req), IFLA_GROUP, group); if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) exit(2); return 0; } } ll_init_map(&rth); if (!(flags & NLM_F_CREATE)) { if (!dev) { fprintf(stderr, "Not enough information: \"dev\" " "argument is required.\n"); exit(-1); } req.i.ifi_index = ll_name_to_index(dev); if (req.i.ifi_index == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", dev); return -1; } } else { /* Allow "ip link add dev" and "ip link add name" */ if (!name) name = dev; if (link) { int ifindex; ifindex = ll_name_to_index(link); if (ifindex == 0) { fprintf(stderr, "Cannot find device \"%s\"\n", link); return -1; } addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4); } } if (name) { len = strlen(name) + 1; if (len == 1) invarg("\"\" is not a valid device identifier\n", "name"); if (len > IFNAMSIZ) invarg("\"name\" too long\n", name); addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len); } if (type) { 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, strlen(type)); lu = get_link_kind(type); if (lu && argc) { struct rtattr * data = NLMSG_TAIL(&req.n); addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0); if (lu->parse_opt && lu->parse_opt(lu, argc, argv, &req.n)) return -1; data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; } else if (argc) { if (matches(*argv, "help") == 0) usage(); fprintf(stderr, "Garbage instead of arguments \"%s ...\". " "Try \"ip link help\".\n", *argv); return -1; } linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; } else if (flags & NLM_F_CREATE) { fprintf(stderr, "Not enough information: \"type\" argument " "is required\n"); return -1; } if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) exit(2); return 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 || matches(*argv, "dsfield") == 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, "oif") == 0) { NEXT_ARG(); addattr_l(&req.n, sizeof(req), FRA_OIFNAME, *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) < 0) return 2; return 0; }
/* Add/Delete IP address to a specific interface_t */ int netlink_ipaddress(ip_address_t *ipaddress, int cmd) { struct ifa_cacheinfo cinfo; int status = 1; 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)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = (cmd == IPADDRESS_DEL) ? RTM_DELADDR : RTM_NEWADDR; req.ifa = ipaddress->ifa; if (IP_IS6(ipaddress)) { if (cmd == IPADDRESS_ADD) { /* Mark IPv6 address as deprecated (rfc3484) in order to prevent * using VRRP VIP as source address in healthchecking use cases. */ if (ipaddress->ifa.ifa_prefixlen == 128) { memset(&cinfo, 0, sizeof(cinfo)); cinfo.ifa_prefered = 0; cinfo.ifa_valid = INFINITY_LIFE_TIME; log_message(LOG_INFO, "%s has a prefix length of 128, setting " "preferred_lft to 0", ipaddresstos(NULL, ipaddress)); addattr_l(&req.n, sizeof(req), IFA_CACHEINFO, &cinfo, sizeof(cinfo)); } /* Disable, per VIP, Duplicate Address Detection algorithm (DAD). * Using the nodad flag has the following benefits: * * (1) The address becomes immediately usable after they're * configured. * (2) In the case of a temporary layer-2 / split-brain problem * we can avoid that the active VIP transitions into the * dadfailed phase and stays there forever - leaving us * without service. HA/VRRP setups have their own "DAD"-like * functionality, so it's not really needed from the IPv6 stack. */ #ifdef IFA_F_NODAD req.ifa.ifa_flags |= IFA_F_NODAD; #endif } addattr_l(&req.n, sizeof(req), IFA_LOCAL, &ipaddress->u.sin6_addr, sizeof(ipaddress->u.sin6_addr)); } else { addattr_l(&req.n, sizeof(req), IFA_LOCAL, &ipaddress->u.sin.sin_addr, sizeof(ipaddress->u.sin.sin_addr)); if (cmd == IPADDRESS_ADD) { if (ipaddress->u.sin.sin_brd.s_addr) addattr_l(&req.n, sizeof(req), IFA_BROADCAST, &ipaddress->u.sin.sin_brd, sizeof(ipaddress->u.sin.sin_brd)); } else { /* IPADDRESS_DEL */ addattr_l(&req.n, sizeof(req), IFA_ADDRESS, &ipaddress->u.sin.sin_addr, sizeof(ipaddress->u.sin.sin_addr)); } } if (cmd == IPADDRESS_ADD) if (ipaddress->label) addattr_l(&req.n, sizeof (req), IFA_LABEL, ipaddress->label, strlen(ipaddress->label) + 1); if (netlink_talk(&nl_cmd, &req.n) < 0) status = -1; return status; }