/* Adresses lookup bootstrap function */ static int netlink_address_lookup(void) { nl_handle_t nlh; int status = 0; if (netlink_socket(&nlh, 0, 0) < 0) return -1; /* IPv4 Address lookup */ if (netlink_request(&nlh, AF_INET, RTM_GETADDR) < 0) { status = -1; goto end_addr; } status = netlink_parse_info(netlink_if_address_filter, &nlh, NULL); /* IPv6 Address lookup */ if (netlink_request(&nlh, AF_INET6, RTM_GETADDR) < 0) { status = -1; goto end_addr; } status = netlink_parse_info(netlink_if_address_filter, &nlh, NULL); end_addr: netlink_close(&nlh); return status; }
static int ip_addr_add(int family, int ifindex, void *addr, void *bcast, void *acast, int prefix) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; struct ip_req *ip_req; int addrlen; int err; addrlen = family == AF_INET ? sizeof(struct in_addr) : sizeof(struct in6_addr); err = netlink_open(&nlh, NETLINK_ROUTE); if (err) return err; err = -ENOMEM; nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!nlmsg) goto out; answer = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!answer) goto out; ip_req = (struct ip_req *)nlmsg; ip_req->nlmsg.nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); ip_req->nlmsg.nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; ip_req->nlmsg.nlmsghdr.nlmsg_type = RTM_NEWADDR; ip_req->ifa.ifa_prefixlen = prefix; ip_req->ifa.ifa_index = ifindex; ip_req->ifa.ifa_family = family; ip_req->ifa.ifa_scope = 0; err = -EINVAL; if (nla_put_buffer(nlmsg, IFA_LOCAL, addr, addrlen)) goto out; if (nla_put_buffer(nlmsg, IFA_ADDRESS, addr, addrlen)) goto out; if (nla_put_buffer(nlmsg, IFA_BROADCAST, bcast, addrlen)) goto out; /* TODO : multicast, anycast with ipv6 */ err = -EPROTONOSUPPORT; if (family == AF_INET6 && (memcmp(bcast, &in6addr_any, sizeof(in6addr_any)) || memcmp(acast, &in6addr_any, sizeof(in6addr_any)))) goto out; err = netlink_transaction(&nlh, nlmsg, answer); out: netlink_close(&nlh); nlmsg_free(answer); nlmsg_free(nlmsg); return err; }
/* Adresses lookup bootstrap function */ static int netlink_address_lookup(void) { nl_handle_t nlh; int status = 0; int ret, flags; if (netlink_socket(&nlh, 0) < 0) return -1; /* Set blocking flag */ ret = netlink_set_block(&nlh, &flags); if (ret < 0) log_message(LOG_INFO, "Netlink: Warning, couldn't set " "blocking flag to netlink socket..."); /* IPv4 Address lookup */ if (netlink_request(&nlh, AF_INET, RTM_GETADDR) < 0) { status = -1; goto end_addr; } status = netlink_parse_info(netlink_if_address_filter, &nlh, NULL); /* IPv6 Address lookup */ if (netlink_request(&nlh, AF_INET6, RTM_GETADDR) < 0) { status = -1; goto end_addr; } status = netlink_parse_info(netlink_if_address_filter, &nlh, NULL); end_addr: netlink_close(&nlh); return status; }
int lxc_netdev_delete_by_index(int ifindex) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; struct link_req *link_req; int err; err = netlink_open(&nlh, NETLINK_ROUTE); if (err) return err; err = -ENOMEM; nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!nlmsg) goto out; answer = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!answer) goto out; link_req = (struct link_req *)nlmsg; link_req->ifinfomsg.ifi_family = AF_UNSPEC; link_req->ifinfomsg.ifi_index = ifindex; nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); nlmsg->nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST; nlmsg->nlmsghdr.nlmsg_type = RTM_DELLINK; err = netlink_transaction(&nlh, nlmsg, answer); out: netlink_close(&nlh); nlmsg_free(answer); nlmsg_free(nlmsg); return err; }
/* Interfaces lookup bootstrap function */ int netlink_interface_lookup(void) { nl_handle_t nlh; int status = 0; int ret, flags; if (netlink_socket(&nlh, 0) < 0) return -1; /* Set blocking flag */ ret = netlink_set_block(&nlh, &flags); if (ret < 0) log_message(LOG_INFO, "Netlink: Warning, couldn't set " "blocking flag to netlink socket..."); /* Interface lookup */ if (netlink_request(&nlh, AF_PACKET, RTM_GETLINK) < 0) { status = -1; goto end_int; } status = netlink_parse_info(netlink_if_link_filter, &nlh, NULL); end_int: netlink_close(&nlh); return status; }
static int netlink_open(struct netlink_fd *fd) { int buf = 16 * 1024; fd->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); fd->seq = time(NULL); if (fd->fd < 0) { perror("Cannot open netlink socket"); return FALSE; } fcntl(fd->fd, F_SETFD, FD_CLOEXEC); if (setsockopt(fd->fd, SOL_SOCKET, SO_SNDBUF, &buf, sizeof(buf)) < 0) { perror("SO_SNDBUF"); goto error; } if (setsockopt(fd->fd, SOL_SOCKET, SO_RCVBUF, &buf, sizeof(buf)) < 0) { perror("SO_RCVBUF"); goto error; } return TRUE; error: netlink_close(fd); return FALSE; }
static int ip_gateway_add(int family, int ifindex, void *gw) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; struct rt_req *rt_req; int addrlen; int err; addrlen = family == AF_INET ? sizeof(struct in_addr) : sizeof(struct in6_addr); err = netlink_open(&nlh, NETLINK_ROUTE); if (err) return err; err = -ENOMEM; nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!nlmsg) goto out; answer = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!answer) goto out; rt_req = (struct rt_req *)nlmsg; rt_req->nlmsg.nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); rt_req->nlmsg.nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; rt_req->nlmsg.nlmsghdr.nlmsg_type = RTM_NEWROUTE; rt_req->rt.rtm_family = family; rt_req->rt.rtm_table = RT_TABLE_MAIN; rt_req->rt.rtm_scope = RT_SCOPE_UNIVERSE; rt_req->rt.rtm_protocol = RTPROT_BOOT; rt_req->rt.rtm_type = RTN_UNICAST; /* "default" destination */ rt_req->rt.rtm_dst_len = 0; err = -EINVAL; if (nla_put_buffer(nlmsg, RTA_GATEWAY, gw, addrlen)) goto out; /* Adding the interface index enables the use of link-local * addresses for the gateway */ if (nla_put_u32(nlmsg, RTA_OIF, ifindex)) goto out; err = netlink_transaction(&nlh, nlmsg, answer); out: netlink_close(&nlh); nlmsg_free(answer); nlmsg_free(nlmsg); return err; }
int close(int fd) { libc_func(close, int, int); netlink_close(fd); ioctl_emulate_close(fd); ioctl_record_close(fd); script_record_close(fd); return _close(fd); }
int lxc_device_rename(const char *oldname, const char *newname) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; struct link_req *link_req; int index, len, err = -1; if (netlink_open(&nlh, NETLINK_ROUTE)) return -1; len = strlen(oldname); if (len == 1 || len > IFNAMSIZ) goto out; len = strlen(newname); if (len == 1 || len > IFNAMSIZ) goto out; nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!nlmsg) goto out; answer = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!answer) goto out; index = if_nametoindex(oldname); if (!index) goto out; link_req = (struct link_req *)nlmsg; link_req->ifinfomsg.ifi_family = AF_UNSPEC; link_req->ifinfomsg.ifi_index = index; nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); nlmsg->nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST; nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; if (nla_put_string(nlmsg, IFLA_IFNAME, newname)) goto out; if (netlink_transaction(&nlh, nlmsg, answer)) goto out; err = 0; out: netlink_close(&nlh); nlmsg_free(answer); nlmsg_free(nlmsg); return err; }
int fclose(FILE * stream) { libc_func(fclose, int, FILE *); int fd = fileno(stream); if (fd >= 0) { netlink_close(fd); ioctl_emulate_close(fd); ioctl_record_close(fd); script_record_close(fd); } return _fclose(stream); }
static int netdev_set_flag(const char *name, int flag) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; struct link_req *link_req; int index, len, err; err = netlink_open(&nlh, NETLINK_ROUTE); if (err) return err; err = -EINVAL; len = strlen(name); if (len == 1 || len >= IFNAMSIZ) goto out; err = -ENOMEM; nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!nlmsg) goto out; answer = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!answer) goto out; err = -EINVAL; index = if_nametoindex(name); if (!index) goto out; link_req = (struct link_req *)nlmsg; link_req->ifinfomsg.ifi_family = AF_UNSPEC; link_req->ifinfomsg.ifi_index = index; link_req->ifinfomsg.ifi_change |= IFF_UP; link_req->ifinfomsg.ifi_flags |= flag; nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; err = netlink_transaction(&nlh, nlmsg, answer); out: netlink_close(&nlh); nlmsg_free(nlmsg); nlmsg_free(answer); return err; }
/* Interfaces lookup bootstrap function */ int netlink_interface_lookup(void) { nl_handle_t nlh; int status = 0; if (netlink_socket(&nlh, 0, 0) < 0) return -1; /* Interface lookup */ if (netlink_request(&nlh, AF_PACKET, RTM_GETLINK) < 0) { status = -1; goto end_int; } status = netlink_parse_info(netlink_if_link_filter, &nlh, NULL); end_int: netlink_close(&nlh); return status; }
int lxc_netdev_move_by_index(int ifindex, pid_t pid, const char* ifname) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL; struct ifinfomsg *ifi; int err; err = netlink_open(&nlh, NETLINK_ROUTE); if (err) return err; err = -ENOMEM; nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!nlmsg) goto out; nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK; ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg)); if (!ifi) goto out; ifi->ifi_family = AF_UNSPEC; ifi->ifi_index = ifindex; if (nla_put_u32(nlmsg, IFLA_NET_NS_PID, pid)) goto out; if (ifname != NULL) { if (nla_put_string(nlmsg, IFLA_IFNAME, ifname)) goto out; } err = netlink_transaction(&nlh, nlmsg, nlmsg); out: netlink_close(&nlh); nlmsg_free(nlmsg); return err; }
int lxc_netdev_move(char *ifname, pid_t pid) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL; struct link_req *link_req; int err, index; index = if_nametoindex(ifname); if (!ifname) return -EINVAL; err = netlink_open(&nlh, NETLINK_ROUTE); if (err) return err; err = -ENOMEM; nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!nlmsg) goto out; link_req = (struct link_req *)nlmsg; link_req->ifinfomsg.ifi_family = AF_UNSPEC; link_req->ifinfomsg.ifi_index = index; nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; if (nla_put_u32(nlmsg, IFLA_NET_NS_PID, pid)) goto out; err = netlink_transaction(&nlh, nlmsg, nlmsg); out: netlink_close(&nlh); nlmsg_free(nlmsg); return err; }
void kernel_netlink_close(void) { netlink_close(&nl_kernel); netlink_close(&nl_cmd); }
int lxc_veth_create(const char *name1, const char *name2) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; struct link_req *link_req; struct rtattr *nest1, *nest2, *nest3; int len, err; err = netlink_open(&nlh, NETLINK_ROUTE); if (err) return err; err = -EINVAL; len = strlen(name1); if (len == 1 || len >= IFNAMSIZ) goto out; len = strlen(name2); if (len == 1 || len >= IFNAMSIZ) goto out; err = -ENOMEM; nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!nlmsg) goto out; answer = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!answer) goto out; link_req = (struct link_req *)nlmsg; link_req->ifinfomsg.ifi_family = AF_UNSPEC; nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK; nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; err = -EINVAL; nest1 = nla_begin_nested(nlmsg, IFLA_LINKINFO); if (!nest1) goto out; if (nla_put_string(nlmsg, IFLA_INFO_KIND, "veth")) goto out; nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA); if (!nest2) goto out; nest3 = nla_begin_nested(nlmsg, VETH_INFO_PEER); if (!nest3) goto out; nlmsg->nlmsghdr.nlmsg_len += sizeof(struct ifinfomsg); if (nla_put_string(nlmsg, IFLA_IFNAME, name2)) goto out; nla_end_nested(nlmsg, nest3); nla_end_nested(nlmsg, nest2); nla_end_nested(nlmsg, nest1); if (nla_put_string(nlmsg, IFLA_IFNAME, name1)) goto out; err = netlink_transaction(&nlh, nlmsg, answer); out: netlink_close(&nlh); nlmsg_free(answer); nlmsg_free(nlmsg); return err; }
static int genetlink_resolve_family(const char *family) { struct nl_handler handler; struct nlattr *attr; struct genlmsg *request, *reply; struct genlmsghdr *genlmsghdr; int len, ret; request = genlmsg_alloc(GENLMSG_GOOD_SIZE); if (!request) return -ENOMEM; reply = genlmsg_alloc(GENLMSG_GOOD_SIZE); if (!reply) { genlmsg_free(request); return -ENOMEM; } request->nlmsghdr.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); request->nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; request->nlmsghdr.nlmsg_type = GENL_ID_CTRL; genlmsghdr = NLMSG_DATA(&request->nlmsghdr); genlmsghdr->cmd = CTRL_CMD_GETFAMILY; ret = netlink_open(&handler, NETLINK_GENERIC); if (ret) goto out; ret = nla_put_string((struct nlmsg *)&request->nlmsghdr, CTRL_ATTR_FAMILY_NAME, family); if (ret) goto out_close; ret = netlink_transaction(&handler, (struct nlmsg *)&request->nlmsghdr, (struct nlmsg *)&reply->nlmsghdr); if (ret < 0) goto out_close; genlmsghdr = NLMSG_DATA(&reply->nlmsghdr); len = reply->nlmsghdr.nlmsg_len; ret = -ENOMSG; if (reply->nlmsghdr.nlmsg_type != GENL_ID_CTRL) goto out_close; if (genlmsghdr->cmd != CTRL_CMD_NEWFAMILY) goto out_close; ret = -EMSGSIZE; len -= NLMSG_LENGTH(GENL_HDRLEN); if (len < 0) goto out_close; attr = (struct nlattr *)GENLMSG_DATA(reply); attr = (struct nlattr *)((char *)attr + NLA_ALIGN(attr->nla_len)); ret = -ENOMSG; if (attr->nla_type != CTRL_ATTR_FAMILY_ID) goto out_close; ret = *(__u16 *) NLA_DATA(attr); out_close: netlink_close(&handler); out: genlmsg_free(request); genlmsg_free(reply); return ret; }
extern int rtnetlink_close(struct rtnl_handler *handler) { return netlink_close(&handler->nlh); }
static int netlink_receive(struct netlink_fd *fd, struct nlmsghdr *reply) { struct sockaddr_nl nladdr; struct iovec iov; struct msghdr msg = { .msg_name = &nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = &iov, .msg_iovlen = 1, }; int got_reply = FALSE, len; char buf[16*1024]; iov.iov_base = buf; while (!got_reply) { int status; struct nlmsghdr *h; iov.iov_len = sizeof(buf); status = recvmsg(fd->fd, &msg, MSG_DONTWAIT); if (status < 0) { if (errno == EINTR) continue; if (errno == EAGAIN) return reply == NULL; fprintf(stderr, "Netlink overrun\n"); continue; } if (status == 0) { fprintf(stderr, "Netlink returned EOF\n"); return FALSE; } h = (struct nlmsghdr *) buf; while (NLMSG_OK(h, status)) { if (reply != NULL && h->nlmsg_seq == reply->nlmsg_seq) { len = h->nlmsg_len; if (len > reply->nlmsg_len) { fprintf(stderr, "Netlink message " "truncated\n"); len = reply->nlmsg_len; } memcpy(reply, h, len); got_reply = TRUE; } else if (h->nlmsg_type != NLMSG_DONE) { fprintf(stderr, "Unknown NLmsg: 0x%08x, len %d\n", h->nlmsg_type, h->nlmsg_len); } h = NLMSG_NEXT(h, status); } } return TRUE; } static int netlink_send(struct netlink_fd *fd, struct nlmsghdr *req) { struct sockaddr_nl nladdr; struct iovec iov = { .iov_base = (void*) req, .iov_len = req->nlmsg_len }; struct msghdr msg = { .msg_name = &nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = &iov, .msg_iovlen = 1, }; int status; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; req->nlmsg_seq = ++fd->seq; status = sendmsg(fd->fd, &msg, 0); if (status < 0) { fprintf(stderr, "Cannot talk to rtnetlink\n"); return FALSE; } return TRUE; } static int netlink_talk(struct nlmsghdr *req, size_t replysize, struct nlmsghdr *reply) { struct netlink_fd fd; int ret = FALSE; if (!netlink_open(&fd)) return FALSE; if (reply == NULL) req->nlmsg_flags |= NLM_F_ACK; if (!netlink_send(&fd, req)) goto out; if (reply != NULL) { reply->nlmsg_len = replysize; ret = netlink_receive(&fd, reply); } else { ret = TRUE; } out: netlink_close(&fd); return ret; } int netlink_route_get(struct sockaddr *dst, u_int16_t *mtu, char *ifname) { struct { struct nlmsghdr n; union { struct rtmsg r; struct ifinfomsg i; }; char buf[1024]; } req; struct rtmsg *r = NLMSG_DATA(&req.n); struct rtattr *rta[RTA_MAX+1]; struct rtattr *rtax[RTAX_MAX+1]; struct rtattr *ifla[IFLA_MAX+1]; int index; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_GETROUTE; req.r.rtm_family = dst->sa_family; netlink_add_rtaddr_l(&req.n, sizeof(req), RTA_DST, dst); req.r.rtm_dst_len = 32; if (!netlink_talk(&req.n, sizeof(req), &req.n)) return FALSE; netlink_parse_rtattr(rta, RTA_MAX, RTM_RTA(r), RTM_PAYLOAD(&req.n)); if (mtu != NULL) { if (rta[RTA_METRICS] == NULL) return FALSE; netlink_parse_rtattr(rtax, RTAX_MAX, RTA_DATA(rta[RTA_METRICS]), RTA_PAYLOAD(rta[RTA_METRICS])); if (rtax[RTAX_MTU] == NULL) return FALSE; *mtu = *(int*) RTA_DATA(rtax[RTAX_MTU]); } if (ifname != NULL) { if (rta[RTA_OIF] == NULL) return FALSE; index = *(int*) RTA_DATA(rta[RTA_OIF]); 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_GETLINK; req.i.ifi_index = index; if (!netlink_talk(&req.n, sizeof(req), &req.n)) return FALSE; netlink_parse_rtattr(ifla, IFLA_MAX, IFLA_RTA(r), IFLA_PAYLOAD(&req.n)); if (ifla[IFLA_IFNAME] == NULL) return FALSE; memcpy(ifname, RTA_DATA(ifla[IFLA_IFNAME]), RTA_PAYLOAD(ifla[IFLA_IFNAME])); } return TRUE; }