{\rtf1\ansi\ansicpg1252\cocoartf2639 \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fmodern\fcharset0 Courier;} {\colortbl;\red255\green255\blue255;\red0\green0\blue0;} {\*\expandedcolortbl;;\cssrgb\c0\c0\c0;} \paperw11900\paperh16840\margl1440\margr1440\vieww11520\viewh8400\viewkind0 \deftab720 \pard\pardeftab720\partightenfactor0 \f0\fs26 \cf0 \expnd0\expndtw0\kerning0 \outl0\strokewidth0 \strokec2 #define _GNU_SOURCE \ \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ \ static unsigned long long procid;\ \ static bool write_file(const char* file, const char* what, ...)\ \{\ char buf[1024];\ va_list args;\ va_start(args, what);\ vsnprintf(buf, sizeof(buf), what, args);\ va_end(args);\ buf[sizeof(buf) - 1] = 0;\ int len = strlen(buf);\ int fd = open(file, O_WRONLY | O_CLOEXEC);\ if (fd == -1)\ return false;\ if (write(fd, buf, len) != len) \{\ int err = errno;\ close(fd);\ errno = err;\ return false;\ \}\ close(fd);\ return true;\ \}\ \ struct nlmsg \{\ char* pos;\ int nesting;\ struct nlattr* nested[8];\ char buf[4096];\ \};\ \ static void netlink_init(struct nlmsg* nlmsg, int typ, int flags,\ const void* data, int size)\ \{\ memset(nlmsg, 0, sizeof(*nlmsg));\ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;\ hdr->nlmsg_type = typ;\ hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags;\ memcpy(hdr + 1, data, size);\ nlmsg->pos = (char*)(hdr + 1) + NLMSG_ALIGN(size);\ \}\ \ static void netlink_attr(struct nlmsg* nlmsg, int typ,\ const void* data, int size)\ \{\ struct nlattr* attr = (struct nlattr*)nlmsg->pos;\ attr->nla_len = sizeof(*attr) + size;\ attr->nla_type = typ;\ if (size > 0)\ memcpy(attr + 1, data, size);\ nlmsg->pos += NLMSG_ALIGN(attr->nla_len);\ \}\ \ static void netlink_nest(struct nlmsg* nlmsg, int typ)\ \{\ struct nlattr* attr = (struct nlattr*)nlmsg->pos;\ attr->nla_type = typ;\ nlmsg->pos += sizeof(*attr);\ nlmsg->nested[nlmsg->nesting++] = attr;\ \}\ \ static void netlink_done(struct nlmsg* nlmsg)\ \{\ struct nlattr* attr = nlmsg->nested[--nlmsg->nesting];\ attr->nla_len = nlmsg->pos - (char*)attr;\ \}\ \ static int netlink_send_ext(struct nlmsg* nlmsg, int sock,\ uint16_t reply_type, int* reply_len, bool dofail)\ \{\ if (nlmsg->pos > nlmsg->buf + sizeof(nlmsg->buf) || nlmsg->nesting)\ exit(1);\ struct nlmsghdr* hdr = (struct nlmsghdr*)nlmsg->buf;\ hdr->nlmsg_len = nlmsg->pos - nlmsg->buf;\ struct sockaddr_nl addr;\ memset(&addr, 0, sizeof(addr));\ addr.nl_family = AF_NETLINK;\ ssize_t n = sendto(sock, nlmsg->buf, hdr->nlmsg_len, 0, (struct sockaddr*)&addr, sizeof(addr));\ if (n != (ssize_t)hdr->nlmsg_len) \{\ if (dofail)\ exit(1);\ return -1;\ \}\ n = recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);\ if (reply_len)\ *reply_len = 0;\ if (n < 0) \{\ if (dofail)\ exit(1);\ return -1;\ \}\ if (n < (ssize_t)sizeof(struct nlmsghdr)) \{\ errno = EINVAL;\ if (dofail)\ exit(1);\ return -1;\ \}\ if (hdr->nlmsg_type == NLMSG_DONE)\ return 0;\ if (reply_len && hdr->nlmsg_type == reply_type) \{\ *reply_len = n;\ return 0;\ \}\ if (n < (ssize_t)(sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr))) \{\ errno = EINVAL;\ if (dofail)\ exit(1);\ return -1;\ \}\ if (hdr->nlmsg_type != NLMSG_ERROR) \{\ errno = EINVAL;\ if (dofail)\ exit(1);\ return -1;\ \}\ errno = -((struct nlmsgerr*)(hdr + 1))->error;\ return -errno;\ \}\ \ static int netlink_send(struct nlmsg* nlmsg, int sock)\ \{\ return netlink_send_ext(nlmsg, sock, 0, NULL, true);\ \}\ \ static int netlink_query_family_id(struct nlmsg* nlmsg, int sock, const char* family_name, bool dofail)\ \{\ struct genlmsghdr genlhdr;\ memset(&genlhdr, 0, sizeof(genlhdr));\ genlhdr.cmd = CTRL_CMD_GETFAMILY;\ netlink_init(nlmsg, GENL_ID_CTRL, 0, &genlhdr, sizeof(genlhdr));\ netlink_attr(nlmsg, CTRL_ATTR_FAMILY_NAME, family_name, strnlen(family_name, GENL_NAMSIZ - 1) + 1);\ int n = 0;\ int err = netlink_send_ext(nlmsg, sock, GENL_ID_CTRL, &n, dofail);\ if (err < 0) \{\ return -1;\ \}\ uint16_t id = 0;\ struct nlattr* attr = (struct nlattr*)(nlmsg->buf + NLMSG_HDRLEN + NLMSG_ALIGN(sizeof(genlhdr)));\ for (; (char*)attr < nlmsg->buf + n; attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) \{\ if (attr->nla_type == CTRL_ATTR_FAMILY_ID) \{\ id = *(uint16_t*)(attr + 1);\ break;\ \}\ \}\ if (!id) \{\ errno = EINVAL;\ return -1;\ \}\ recv(sock, nlmsg->buf, sizeof(nlmsg->buf), 0);\ return id;\ \}\ \ static int netlink_next_msg(struct nlmsg* nlmsg, unsigned int offset,\ unsigned int total_len)\ \{\ struct nlmsghdr* hdr = (struct nlmsghdr*)(nlmsg->buf + offset);\ if (offset == total_len || offset + hdr->nlmsg_len > total_len)\ return -1;\ return hdr->nlmsg_len;\ \}\ \ static void netlink_add_device_impl(struct nlmsg* nlmsg, const char* type,\ const char* name)\ \{\ struct ifinfomsg hdr;\ memset(&hdr, 0, sizeof(hdr));\ netlink_init(nlmsg, RTM_NEWLINK, NLM_F_EXCL | NLM_F_CREATE, &hdr, sizeof(hdr));\ if (name)\ netlink_attr(nlmsg, IFLA_IFNAME, name, strlen(name));\ netlink_nest(nlmsg, IFLA_LINKINFO);\ netlink_attr(nlmsg, IFLA_INFO_KIND, type, strlen(type));\ \}\ \ static void netlink_add_device(struct nlmsg* nlmsg, int sock, const char* type,\ const char* name)\ \{\ netlink_add_device_impl(nlmsg, type, name);\ netlink_done(nlmsg);\ int err = netlink_send(nlmsg, sock);\ if (err < 0) \{\ \}\ \}\ \ static void netlink_add_veth(struct nlmsg* nlmsg, int sock, const char* name,\ const char* peer)\ \{\ netlink_add_device_impl(nlmsg, "veth", name);\ netlink_nest(nlmsg, IFLA_INFO_DATA);\ netlink_nest(nlmsg, VETH_INFO_PEER);\ nlmsg->pos += sizeof(struct ifinfomsg);\ netlink_attr(nlmsg, IFLA_IFNAME, peer, strlen(peer));\ netlink_done(nlmsg);\ netlink_done(nlmsg);\ netlink_done(nlmsg);\ int err = netlink_send(nlmsg, sock);\ if (err < 0) \{\ \}\ \}\ \ static void netlink_add_hsr(struct nlmsg* nlmsg, int sock, const char* name,\ const char* slave1, const char* slave2)\ \{\ netlink_add_device_impl(nlmsg, "hsr", name);\ netlink_nest(nlmsg, IFLA_INFO_DATA);\ int ifindex1 = if_nametoindex(slave1);\ netlink_attr(nlmsg, IFLA_HSR_SLAVE1, &ifindex1, sizeof(ifindex1));\ int ifindex2 = if_nametoindex(slave2);\ netlink_attr(nlmsg, IFLA_HSR_SLAVE2, &ifindex2, sizeof(ifindex2));\ netlink_done(nlmsg);\ netlink_done(nlmsg);\ int err = netlink_send(nlmsg, sock);\ if (err < 0) \{\ \}\ \}\ \ static void netlink_add_linked(struct nlmsg* nlmsg, int sock, const char* type, const char* name, const char* link)\ \{\ netlink_add_device_impl(nlmsg, type, name);\ netlink_done(nlmsg);\ int ifindex = if_nametoindex(link);\ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));\ int err = netlink_send(nlmsg, sock);\ if (err < 0) \{\ \}\ \}\ \ static void netlink_add_vlan(struct nlmsg* nlmsg, int sock, const char* name, const char* link, uint16_t id, uint16_t proto)\ \{\ netlink_add_device_impl(nlmsg, "vlan", name);\ netlink_nest(nlmsg, IFLA_INFO_DATA);\ netlink_attr(nlmsg, IFLA_VLAN_ID, &id, sizeof(id));\ netlink_attr(nlmsg, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));\ netlink_done(nlmsg);\ netlink_done(nlmsg);\ int ifindex = if_nametoindex(link);\ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));\ int err = netlink_send(nlmsg, sock);\ if (err < 0) \{\ \}\ \}\ \ static void netlink_add_macvlan(struct nlmsg* nlmsg, int sock, const char* name, const char* link)\ \{\ netlink_add_device_impl(nlmsg, "macvlan", name);\ netlink_nest(nlmsg, IFLA_INFO_DATA);\ uint32_t mode = MACVLAN_MODE_BRIDGE;\ netlink_attr(nlmsg, IFLA_MACVLAN_MODE, &mode, sizeof(mode));\ netlink_done(nlmsg);\ netlink_done(nlmsg);\ int ifindex = if_nametoindex(link);\ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));\ int err = netlink_send(nlmsg, sock);\ if (err < 0) \{\ \}\ \}\ \ static void netlink_add_geneve(struct nlmsg* nlmsg, int sock, const char* name, uint32_t vni, struct in_addr* addr4, struct in6_addr* addr6)\ \{\ netlink_add_device_impl(nlmsg, "geneve", name);\ netlink_nest(nlmsg, IFLA_INFO_DATA);\ netlink_attr(nlmsg, IFLA_GENEVE_ID, &vni, sizeof(vni));\ if (addr4)\ netlink_attr(nlmsg, IFLA_GENEVE_REMOTE, addr4, sizeof(*addr4));\ if (addr6)\ netlink_attr(nlmsg, IFLA_GENEVE_REMOTE6, addr6, sizeof(*addr6));\ netlink_done(nlmsg);\ netlink_done(nlmsg);\ int err = netlink_send(nlmsg, sock);\ if (err < 0) \{\ \}\ \}\ \ #define IFLA_IPVLAN_FLAGS 2\ #define IPVLAN_MODE_L3S 2\ #undef IPVLAN_F_VEPA\ #define IPVLAN_F_VEPA 2\ \ static void netlink_add_ipvlan(struct nlmsg* nlmsg, int sock, const char* name, const char* link, uint16_t mode, uint16_t flags)\ \{\ netlink_add_device_impl(nlmsg, "ipvlan", name);\ netlink_nest(nlmsg, IFLA_INFO_DATA);\ netlink_attr(nlmsg, IFLA_IPVLAN_MODE, &mode, sizeof(mode));\ netlink_attr(nlmsg, IFLA_IPVLAN_FLAGS, &flags, sizeof(flags));\ netlink_done(nlmsg);\ netlink_done(nlmsg);\ int ifindex = if_nametoindex(link);\ netlink_attr(nlmsg, IFLA_LINK, &ifindex, sizeof(ifindex));\ int err = netlink_send(nlmsg, sock);\ if (err < 0) \{\ \}\ \}\ \ static void netlink_device_change(struct nlmsg* nlmsg, int sock, const char* name, bool up,\ const char* master, const void* mac, int macsize,\ const char* new_name)\ \{\ struct ifinfomsg hdr;\ memset(&hdr, 0, sizeof(hdr));\ if (up)\ hdr.ifi_flags = hdr.ifi_change = IFF_UP;\ hdr.ifi_index = if_nametoindex(name);\ netlink_init(nlmsg, RTM_NEWLINK, 0, &hdr, sizeof(hdr));\ if (new_name)\ netlink_attr(nlmsg, IFLA_IFNAME, new_name, strlen(new_name));\ if (master) \{\ int ifindex = if_nametoindex(master);\ netlink_attr(nlmsg, IFLA_MASTER, &ifindex, sizeof(ifindex));\ \}\ if (macsize)\ netlink_attr(nlmsg, IFLA_ADDRESS, mac, macsize);\ int err = netlink_send(nlmsg, sock);\ if (err < 0) \{\ \}\ \}\ \ static int netlink_add_addr(struct nlmsg* nlmsg, int sock, const char* dev,\ const void* addr, int addrsize)\ \{\ struct ifaddrmsg hdr;\ memset(&hdr, 0, sizeof(hdr));\ hdr.ifa_family = addrsize == 4 ? AF_INET : AF_INET6;\ hdr.ifa_prefixlen = addrsize == 4 ? 24 : 120;\ hdr.ifa_scope = RT_SCOPE_UNIVERSE;\ hdr.ifa_index = if_nametoindex(dev);\ netlink_init(nlmsg, RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, &hdr, sizeof(hdr));\ netlink_attr(nlmsg, IFA_LOCAL, addr, addrsize);\ netlink_attr(nlmsg, IFA_ADDRESS, addr, addrsize);\ return netlink_send(nlmsg, sock);\ \}\ \ static void netlink_add_addr4(struct nlmsg* nlmsg, int sock,\ const char* dev, const char* addr)\ \{\ struct in_addr in_addr;\ inet_pton(AF_INET, addr, &in_addr);\ int err = netlink_add_addr(nlmsg, sock, dev, &in_addr, sizeof(in_addr));\ if (err < 0) \{\ \}\ \}\ \ static void netlink_add_addr6(struct nlmsg* nlmsg, int sock,\ const char* dev, const char* addr)\ \{\ struct in6_addr in6_addr;\ inet_pton(AF_INET6, addr, &in6_addr);\ int err = netlink_add_addr(nlmsg, sock, dev, &in6_addr, sizeof(in6_addr));\ if (err < 0) \{\ \}\ \}\ \ static struct nlmsg nlmsg;\ \ #define DEVLINK_FAMILY_NAME "devlink"\ \ #define DEVLINK_CMD_PORT_GET 5\ #define DEVLINK_ATTR_BUS_NAME 1\ #define DEVLINK_ATTR_DEV_NAME 2\ #define DEVLINK_ATTR_NETDEV_NAME 7\ \ static struct nlmsg nlmsg2;\ \ static void initialize_devlink_ports(const char* bus_name, const char* dev_name,\ const char* netdev_prefix)\ \{\ struct genlmsghdr genlhdr;\ int len, total_len, id, err, offset;\ uint16_t netdev_index;\ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);\ if (sock == -1)\ exit(1);\ int rtsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);\ if (rtsock == -1)\ exit(1);\ id = netlink_query_family_id(&nlmsg, sock, DEVLINK_FAMILY_NAME, true);\ if (id == -1)\ goto error;\ memset(&genlhdr, 0, sizeof(genlhdr));\ genlhdr.cmd = DEVLINK_CMD_PORT_GET;\ netlink_init(&nlmsg, id, NLM_F_DUMP, &genlhdr, sizeof(genlhdr));\ netlink_attr(&nlmsg, DEVLINK_ATTR_BUS_NAME, bus_name, strlen(bus_name) + 1);\ netlink_attr(&nlmsg, DEVLINK_ATTR_DEV_NAME, dev_name, strlen(dev_name) + 1);\ err = netlink_send_ext(&nlmsg, sock, id, &total_len, true);\ if (err < 0) \{\ goto error;\ \}\ offset = 0;\ netdev_index = 0;\ while ((len = netlink_next_msg(&nlmsg, offset, total_len)) != -1) \{\ struct nlattr* attr = (struct nlattr*)(nlmsg.buf + offset + NLMSG_HDRLEN + NLMSG_ALIGN(sizeof(genlhdr)));\ for (; (char*)attr < nlmsg.buf + offset + len; attr = (struct nlattr*)((char*)attr + NLMSG_ALIGN(attr->nla_len))) \{\ if (attr->nla_type == DEVLINK_ATTR_NETDEV_NAME) \{\ char* port_name;\ char netdev_name[IFNAMSIZ];\ port_name = (char*)(attr + 1);\ snprintf(netdev_name, sizeof(netdev_name), "%s%d", netdev_prefix, netdev_index);\ netlink_device_change(&nlmsg2, rtsock, port_name, true, 0, 0, 0, netdev_name);\ break;\ \}\ \}\ offset += len;\ netdev_index++;\ \}\ error:\ close(rtsock);\ close(sock);\ \}\ \ #define DEV_IPV4 "172.20.20.%d"\ #define DEV_IPV6 "fe80::%02x"\ #define DEV_MAC 0x00aaaaaaaaaa\ \ static void netdevsim_add(unsigned int addr, unsigned int port_count)\ \{\ char buf[16];\ sprintf(buf, "%u %u", addr, port_count);\ if (write_file("/sys/bus/netdevsim/new_device", buf)) \{\ snprintf(buf, sizeof(buf), "netdevsim%d", addr);\ initialize_devlink_ports("netdevsim", buf, "netdevsim");\ \}\ \}\ \ #define WG_GENL_NAME "wireguard"\ enum wg_cmd \{\ WG_CMD_GET_DEVICE,\ WG_CMD_SET_DEVICE,\ \};\ enum wgdevice_attribute \{\ WGDEVICE_A_UNSPEC,\ WGDEVICE_A_IFINDEX,\ WGDEVICE_A_IFNAME,\ WGDEVICE_A_PRIVATE_KEY,\ WGDEVICE_A_PUBLIC_KEY,\ WGDEVICE_A_FLAGS,\ WGDEVICE_A_LISTEN_PORT,\ WGDEVICE_A_FWMARK,\ WGDEVICE_A_PEERS,\ \};\ enum wgpeer_attribute \{\ WGPEER_A_UNSPEC,\ WGPEER_A_PUBLIC_KEY,\ WGPEER_A_PRESHARED_KEY,\ WGPEER_A_FLAGS,\ WGPEER_A_ENDPOINT,\ WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL,\ WGPEER_A_LAST_HANDSHAKE_TIME,\ WGPEER_A_RX_BYTES,\ WGPEER_A_TX_BYTES,\ WGPEER_A_ALLOWEDIPS,\ WGPEER_A_PROTOCOL_VERSION,\ \};\ enum wgallowedip_attribute \{\ WGALLOWEDIP_A_UNSPEC,\ WGALLOWEDIP_A_FAMILY,\ WGALLOWEDIP_A_IPADDR,\ WGALLOWEDIP_A_CIDR_MASK,\ \};\ \ static void netlink_wireguard_setup(void)\ \{\ const char ifname_a[] = "wg0";\ const char ifname_b[] = "wg1";\ const char ifname_c[] = "wg2";\ const char private_a[] = "\\xa0\\x5c\\xa8\\x4f\\x6c\\x9c\\x8e\\x38\\x53\\xe2\\xfd\\x7a\\x70\\xae\\x0f\\xb2\\x0f\\xa1\\x52\\x60\\x0c\\xb0\\x08\\x45\\x17\\x4f\\x08\\x07\\x6f\\x8d\\x78\\x43";\ const char private_b[] = "\\xb0\\x80\\x73\\xe8\\xd4\\x4e\\x91\\xe3\\xda\\x92\\x2c\\x22\\x43\\x82\\x44\\xbb\\x88\\x5c\\x69\\xe2\\x69\\xc8\\xe9\\xd8\\x35\\xb1\\x14\\x29\\x3a\\x4d\\xdc\\x6e";\ const char private_c[] = "\\xa0\\xcb\\x87\\x9a\\x47\\xf5\\xbc\\x64\\x4c\\x0e\\x69\\x3f\\xa6\\xd0\\x31\\xc7\\x4a\\x15\\x53\\xb6\\xe9\\x01\\xb9\\xff\\x2f\\x51\\x8c\\x78\\x04\\x2f\\xb5\\x42";\ const char public_a[] = "\\x97\\x5c\\x9d\\x81\\xc9\\x83\\xc8\\x20\\x9e\\xe7\\x81\\x25\\x4b\\x89\\x9f\\x8e\\xd9\\x25\\xae\\x9f\\x09\\x23\\xc2\\x3c\\x62\\xf5\\x3c\\x57\\xcd\\xbf\\x69\\x1c";\ const char public_b[] = "\\xd1\\x73\\x28\\x99\\xf6\\x11\\xcd\\x89\\x94\\x03\\x4d\\x7f\\x41\\x3d\\xc9\\x57\\x63\\x0e\\x54\\x93\\xc2\\x85\\xac\\xa4\\x00\\x65\\xcb\\x63\\x11\\xbe\\x69\\x6b";\ const char public_c[] = "\\xf4\\x4d\\xa3\\x67\\xa8\\x8e\\xe6\\x56\\x4f\\x02\\x02\\x11\\x45\\x67\\x27\\x08\\x2f\\x5c\\xeb\\xee\\x8b\\x1b\\xf5\\xeb\\x73\\x37\\x34\\x1b\\x45\\x9b\\x39\\x22";\ const uint16_t listen_a = 20001;\ const uint16_t listen_b = 20002;\ const uint16_t listen_c = 20003;\ const uint16_t af_inet = AF_INET;\ const uint16_t af_inet6 = AF_INET6;\ const struct sockaddr_in endpoint_b_v4 = \{\ .sin_family = AF_INET,\ .sin_port = htons(listen_b),\ .sin_addr = \{htonl(INADDR_LOOPBACK)\}\};\ const struct sockaddr_in endpoint_c_v4 = \{\ .sin_family = AF_INET,\ .sin_port = htons(listen_c),\ .sin_addr = \{htonl(INADDR_LOOPBACK)\}\};\ struct sockaddr_in6 endpoint_a_v6 = \{\ .sin6_family = AF_INET6,\ .sin6_port = htons(listen_a)\};\ endpoint_a_v6.sin6_addr = in6addr_loopback;\ struct sockaddr_in6 endpoint_c_v6 = \{\ .sin6_family = AF_INET6,\ .sin6_port = htons(listen_c)\};\ endpoint_c_v6.sin6_addr = in6addr_loopback;\ const struct in_addr first_half_v4 = \{0\};\ const struct in_addr second_half_v4 = \{(uint32_t)htonl(128 << 24)\};\ const struct in6_addr first_half_v6 = \{\{\{0\}\}\};\ const struct in6_addr second_half_v6 = \{\{\{0x80\}\}\};\ const uint8_t half_cidr = 1;\ const uint16_t persistent_keepalives[] = \{1, 3, 7, 9, 14, 19\};\ struct genlmsghdr genlhdr = \{\ .cmd = WG_CMD_SET_DEVICE,\ .version = 1\};\ int sock;\ int id, err;\ sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);\ if (sock == -1) \{\ return;\ \}\ id = netlink_query_family_id(&nlmsg, sock, WG_GENL_NAME, true);\ if (id == -1)\ goto error;\ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));\ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_a, strlen(ifname_a) + 1);\ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_a, 32);\ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_a, 2);\ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);\ netlink_nest(&nlmsg, NLA_F_NESTED | 0);\ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);\ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4, sizeof(endpoint_b_v4));\ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, &persistent_keepalives[0], 2);\ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);\ netlink_nest(&nlmsg, NLA_F_NESTED | 0);\ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);\ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4, sizeof(first_half_v4));\ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);\ netlink_done(&nlmsg);\ netlink_nest(&nlmsg, NLA_F_NESTED | 0);\ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);\ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6, sizeof(first_half_v6));\ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);\ netlink_done(&nlmsg);\ netlink_done(&nlmsg);\ netlink_done(&nlmsg);\ netlink_nest(&nlmsg, NLA_F_NESTED | 0);\ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);\ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v6, sizeof(endpoint_c_v6));\ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, &persistent_keepalives[1], 2);\ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);\ netlink_nest(&nlmsg, NLA_F_NESTED | 0);\ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);\ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4, sizeof(second_half_v4));\ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);\ netlink_done(&nlmsg);\ netlink_nest(&nlmsg, NLA_F_NESTED | 0);\ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);\ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6, sizeof(second_half_v6));\ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);\ netlink_done(&nlmsg);\ netlink_done(&nlmsg);\ netlink_done(&nlmsg);\ netlink_done(&nlmsg);\ err = netlink_send(&nlmsg, sock);\ if (err < 0) \{\ \}\ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));\ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_b, strlen(ifname_b) + 1);\ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_b, 32);\ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_b, 2);\ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);\ netlink_nest(&nlmsg, NLA_F_NESTED | 0);\ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);\ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6, sizeof(endpoint_a_v6));\ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, &persistent_keepalives[2], 2);\ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);\ netlink_nest(&nlmsg, NLA_F_NESTED | 0);\ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);\ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4, sizeof(first_half_v4));\ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);\ netlink_done(&nlmsg);\ netlink_nest(&nlmsg, NLA_F_NESTED | 0);\ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);\ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6, sizeof(first_half_v6));\ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);\ netlink_done(&nlmsg);\ netlink_done(&nlmsg);\ netlink_done(&nlmsg);\ netlink_nest(&nlmsg, NLA_F_NESTED | 0);\ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_c, 32);\ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_c_v4, sizeof(endpoint_c_v4));\ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, &persistent_keepalives[3], 2);\ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);\ netlink_nest(&nlmsg, NLA_F_NESTED | 0);\ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);\ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4, sizeof(second_half_v4));\ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);\ netlink_done(&nlmsg);\ netlink_nest(&nlmsg, NLA_F_NESTED | 0);\ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);\ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6, sizeof(second_half_v6));\ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);\ netlink_done(&nlmsg);\ netlink_done(&nlmsg);\ netlink_done(&nlmsg);\ netlink_done(&nlmsg);\ err = netlink_send(&nlmsg, sock);\ if (err < 0) \{\ \}\ netlink_init(&nlmsg, id, 0, &genlhdr, sizeof(genlhdr));\ netlink_attr(&nlmsg, WGDEVICE_A_IFNAME, ifname_c, strlen(ifname_c) + 1);\ netlink_attr(&nlmsg, WGDEVICE_A_PRIVATE_KEY, private_c, 32);\ netlink_attr(&nlmsg, WGDEVICE_A_LISTEN_PORT, &listen_c, 2);\ netlink_nest(&nlmsg, NLA_F_NESTED | WGDEVICE_A_PEERS);\ netlink_nest(&nlmsg, NLA_F_NESTED | 0);\ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_a, 32);\ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_a_v6, sizeof(endpoint_a_v6));\ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, &persistent_keepalives[4], 2);\ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);\ netlink_nest(&nlmsg, NLA_F_NESTED | 0);\ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);\ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v4, sizeof(first_half_v4));\ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);\ netlink_done(&nlmsg);\ netlink_nest(&nlmsg, NLA_F_NESTED | 0);\ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);\ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &first_half_v6, sizeof(first_half_v6));\ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);\ netlink_done(&nlmsg);\ netlink_done(&nlmsg);\ netlink_done(&nlmsg);\ netlink_nest(&nlmsg, NLA_F_NESTED | 0);\ netlink_attr(&nlmsg, WGPEER_A_PUBLIC_KEY, public_b, 32);\ netlink_attr(&nlmsg, WGPEER_A_ENDPOINT, &endpoint_b_v4, sizeof(endpoint_b_v4));\ netlink_attr(&nlmsg, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL, &persistent_keepalives[5], 2);\ netlink_nest(&nlmsg, NLA_F_NESTED | WGPEER_A_ALLOWEDIPS);\ netlink_nest(&nlmsg, NLA_F_NESTED | 0);\ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet, 2);\ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v4, sizeof(second_half_v4));\ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);\ netlink_done(&nlmsg);\ netlink_nest(&nlmsg, NLA_F_NESTED | 0);\ netlink_attr(&nlmsg, WGALLOWEDIP_A_FAMILY, &af_inet6, 2);\ netlink_attr(&nlmsg, WGALLOWEDIP_A_IPADDR, &second_half_v6, sizeof(second_half_v6));\ netlink_attr(&nlmsg, WGALLOWEDIP_A_CIDR_MASK, &half_cidr, 1);\ netlink_done(&nlmsg);\ netlink_done(&nlmsg);\ netlink_done(&nlmsg);\ netlink_done(&nlmsg);\ err = netlink_send(&nlmsg, sock);\ if (err < 0) \{\ \}\ \ error:\ close(sock);\ \}\ static void initialize_netdevices(void)\ \{\ char netdevsim[16];\ sprintf(netdevsim, "netdevsim%d", (int)procid);\ struct \{\ const char* type;\ const char* dev;\ \} devtypes[] = \{\ \{"ip6gretap", "ip6gretap0"\},\ \{"bridge", "bridge0"\},\ \{"vcan", "vcan0"\},\ \{"bond", "bond0"\},\ \{"team", "team0"\},\ \{"dummy", "dummy0"\},\ \{"nlmon", "nlmon0"\},\ \{"caif", "caif0"\},\ \{"batadv", "batadv0"\},\ \{"vxcan", "vxcan1"\},\ \{"netdevsim", netdevsim\},\ \{"veth", 0\},\ \{"xfrm", "xfrm0"\},\ \{"wireguard", "wg0"\},\ \{"wireguard", "wg1"\},\ \{"wireguard", "wg2"\},\ \};\ const char* devmasters[] = \{"bridge", "bond", "team", "batadv"\};\ struct \{\ const char* name;\ int macsize;\ bool noipv6;\ \} devices[] = \{\ \{"lo", ETH_ALEN\},\ \{"sit0", 0\},\ \{"bridge0", ETH_ALEN\},\ \{"vcan0", 0, true\},\ \{"tunl0", 0\},\ \{"gre0", 0\},\ \{"gretap0", ETH_ALEN\},\ \{"ip_vti0", 0\},\ \{"ip6_vti0", 0\},\ \{"ip6tnl0", 0\},\ \{"ip6gre0", 0\},\ \{"ip6gretap0", ETH_ALEN\},\ \{"erspan0", ETH_ALEN\},\ \{"bond0", ETH_ALEN\},\ \{"veth0", ETH_ALEN\},\ \{"veth1", ETH_ALEN\},\ \{"team0", ETH_ALEN\},\ \{"veth0_to_bridge", ETH_ALEN\},\ \{"veth1_to_bridge", ETH_ALEN\},\ \{"veth0_to_bond", ETH_ALEN\},\ \{"veth1_to_bond", ETH_ALEN\},\ \{"veth0_to_team", ETH_ALEN\},\ \{"veth1_to_team", ETH_ALEN\},\ \{"veth0_to_hsr", ETH_ALEN\},\ \{"veth1_to_hsr", ETH_ALEN\},\ \{"hsr0", 0\},\ \{"dummy0", ETH_ALEN\},\ \{"nlmon0", 0\},\ \{"vxcan0", 0, true\},\ \{"vxcan1", 0, true\},\ \{"caif0", ETH_ALEN\},\ \{"batadv0", ETH_ALEN\},\ \{netdevsim, ETH_ALEN\},\ \{"xfrm0", ETH_ALEN\},\ \{"veth0_virt_wifi", ETH_ALEN\},\ \{"veth1_virt_wifi", ETH_ALEN\},\ \{"virt_wifi0", ETH_ALEN\},\ \{"veth0_vlan", ETH_ALEN\},\ \{"veth1_vlan", ETH_ALEN\},\ \{"vlan0", ETH_ALEN\},\ \{"vlan1", ETH_ALEN\},\ \{"macvlan0", ETH_ALEN\},\ \{"macvlan1", ETH_ALEN\},\ \{"ipvlan0", ETH_ALEN\},\ \{"ipvlan1", ETH_ALEN\},\ \{"veth0_macvtap", ETH_ALEN\},\ \{"veth1_macvtap", ETH_ALEN\},\ \{"macvtap0", ETH_ALEN\},\ \{"macsec0", ETH_ALEN\},\ \{"veth0_to_batadv", ETH_ALEN\},\ \{"veth1_to_batadv", ETH_ALEN\},\ \{"batadv_slave_0", ETH_ALEN\},\ \{"batadv_slave_1", ETH_ALEN\},\ \{"geneve0", ETH_ALEN\},\ \{"geneve1", ETH_ALEN\},\ \{"wg0", 0\},\ \{"wg1", 0\},\ \{"wg2", 0\},\ \};\ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);\ if (sock == -1)\ exit(1);\ unsigned i;\ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++)\ netlink_add_device(&nlmsg, sock, devtypes[i].type, devtypes[i].dev);\ for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) \{\ char master[32], slave0[32], veth0[32], slave1[32], veth1[32];\ sprintf(slave0, "%s_slave_0", devmasters[i]);\ sprintf(veth0, "veth0_to_%s", devmasters[i]);\ netlink_add_veth(&nlmsg, sock, slave0, veth0);\ sprintf(slave1, "%s_slave_1", devmasters[i]);\ sprintf(veth1, "veth1_to_%s", devmasters[i]);\ netlink_add_veth(&nlmsg, sock, slave1, veth1);\ sprintf(master, "%s0", devmasters[i]);\ netlink_device_change(&nlmsg, sock, slave0, false, master, 0, 0, NULL);\ netlink_device_change(&nlmsg, sock, slave1, false, master, 0, 0, NULL);\ \}\ netlink_device_change(&nlmsg, sock, "bridge_slave_0", true, 0, 0, 0, NULL);\ netlink_device_change(&nlmsg, sock, "bridge_slave_1", true, 0, 0, 0, NULL);\ netlink_add_veth(&nlmsg, sock, "hsr_slave_0", "veth0_to_hsr");\ netlink_add_veth(&nlmsg, sock, "hsr_slave_1", "veth1_to_hsr");\ netlink_add_hsr(&nlmsg, sock, "hsr0", "hsr_slave_0", "hsr_slave_1");\ netlink_device_change(&nlmsg, sock, "hsr_slave_0", true, 0, 0, 0, NULL);\ netlink_device_change(&nlmsg, sock, "hsr_slave_1", true, 0, 0, 0, NULL);\ netlink_add_veth(&nlmsg, sock, "veth0_virt_wifi", "veth1_virt_wifi");\ netlink_add_linked(&nlmsg, sock, "virt_wifi", "virt_wifi0", "veth1_virt_wifi");\ netlink_add_veth(&nlmsg, sock, "veth0_vlan", "veth1_vlan");\ netlink_add_vlan(&nlmsg, sock, "vlan0", "veth0_vlan", 0, htons(ETH_P_8021Q));\ netlink_add_vlan(&nlmsg, sock, "vlan1", "veth0_vlan", 1, htons(ETH_P_8021AD));\ netlink_add_macvlan(&nlmsg, sock, "macvlan0", "veth1_vlan");\ netlink_add_macvlan(&nlmsg, sock, "macvlan1", "veth1_vlan");\ netlink_add_ipvlan(&nlmsg, sock, "ipvlan0", "veth0_vlan", IPVLAN_MODE_L2, 0);\ netlink_add_ipvlan(&nlmsg, sock, "ipvlan1", "veth0_vlan", IPVLAN_MODE_L3S, IPVLAN_F_VEPA);\ netlink_add_veth(&nlmsg, sock, "veth0_macvtap", "veth1_macvtap");\ netlink_add_linked(&nlmsg, sock, "macvtap", "macvtap0", "veth0_macvtap");\ netlink_add_linked(&nlmsg, sock, "macsec", "macsec0", "veth1_macvtap");\ char addr[32];\ sprintf(addr, DEV_IPV4, 14 + 10);\ struct in_addr geneve_addr4;\ if (inet_pton(AF_INET, addr, &geneve_addr4) <= 0)\ exit(1);\ struct in6_addr geneve_addr6;\ if (inet_pton(AF_INET6, "fc00::01", &geneve_addr6) <= 0)\ exit(1);\ netlink_add_geneve(&nlmsg, sock, "geneve0", 0, &geneve_addr4, 0);\ netlink_add_geneve(&nlmsg, sock, "geneve1", 1, 0, &geneve_addr6);\ netdevsim_add((int)procid, 4);\ netlink_wireguard_setup();\ for (i = 0; i < sizeof(devices) / (sizeof(devices[0])); i++) \{\ char addr[32];\ sprintf(addr, DEV_IPV4, i + 10);\ netlink_add_addr4(&nlmsg, sock, devices[i].name, addr);\ if (!devices[i].noipv6) \{\ sprintf(addr, DEV_IPV6, i + 10);\ netlink_add_addr6(&nlmsg, sock, devices[i].name, addr);\ \}\ uint64_t macaddr = DEV_MAC + ((i + 10ull) << 40);\ netlink_device_change(&nlmsg, sock, devices[i].name, true, 0, &macaddr, devices[i].macsize, NULL);\ \}\ close(sock);\ \}\ static void initialize_netdevices_init(void)\ \{\ int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);\ if (sock == -1)\ exit(1);\ struct \{\ const char* type;\ int macsize;\ bool noipv6;\ bool noup;\ \} devtypes[] = \{\ \{"nr", 7, true\},\ \{"rose", 5, true, true\},\ \};\ unsigned i;\ for (i = 0; i < sizeof(devtypes) / sizeof(devtypes[0]); i++) \{\ char dev[32], addr[32];\ sprintf(dev, "%s%d", devtypes[i].type, (int)procid);\ sprintf(addr, "172.30.%d.%d", i, (int)procid + 1);\ netlink_add_addr4(&nlmsg, sock, dev, addr);\ if (!devtypes[i].noipv6) \{\ sprintf(addr, "fe88::%02x:%02x", i, (int)procid + 1);\ netlink_add_addr6(&nlmsg, sock, dev, addr);\ \}\ int macsize = devtypes[i].macsize;\ uint64_t macaddr = 0xbbbbbb + ((unsigned long long)i << (8 * (macsize - 2))) +\ (procid << (8 * (macsize - 1)));\ netlink_device_change(&nlmsg, sock, dev, !devtypes[i].noup, 0, &macaddr, macsize, NULL);\ \}\ close(sock);\ \}\ \ #define MAX_FDS 30\ \ #define BTPROTO_HCI 1\ #define ACL_LINK 1\ #define SCAN_PAGE 2\ \ typedef struct \{\ uint8_t b[6];\ \} __attribute__((packed)) bdaddr_t;\ \ #define HCI_COMMAND_PKT 1\ #define HCI_EVENT_PKT 4\ #define HCI_VENDOR_PKT 0xff\ \ struct hci_command_hdr \{\ uint16_t opcode;\ uint8_t plen;\ \} __attribute__((packed));\ \ struct hci_event_hdr \{\ uint8_t evt;\ uint8_t plen;\ \} __attribute__((packed));\ \ #define HCI_EV_CONN_COMPLETE 0x03\ struct hci_ev_conn_complete \{\ uint8_t status;\ uint16_t handle;\ bdaddr_t bdaddr;\ uint8_t link_type;\ uint8_t encr_mode;\ \} __attribute__((packed));\ \ #define HCI_EV_CONN_REQUEST 0x04\ struct hci_ev_conn_request \{\ bdaddr_t bdaddr;\ uint8_t dev_class[3];\ uint8_t link_type;\ \} __attribute__((packed));\ \ #define HCI_EV_REMOTE_FEATURES 0x0b\ struct hci_ev_remote_features \{\ uint8_t status;\ uint16_t handle;\ uint8_t features[8];\ \} __attribute__((packed));\ \ #define HCI_EV_CMD_COMPLETE 0x0e\ struct hci_ev_cmd_complete \{\ uint8_t ncmd;\ uint16_t opcode;\ \} __attribute__((packed));\ \ #define HCI_OP_WRITE_SCAN_ENABLE 0x0c1a\ \ #define HCI_OP_READ_BUFFER_SIZE 0x1005\ struct hci_rp_read_buffer_size \{\ uint8_t status;\ uint16_t acl_mtu;\ uint8_t sco_mtu;\ uint16_t acl_max_pkt;\ uint16_t sco_max_pkt;\ \} __attribute__((packed));\ \ #define HCI_OP_READ_BD_ADDR 0x1009\ struct hci_rp_read_bd_addr \{\ uint8_t status;\ bdaddr_t bdaddr;\ \} __attribute__((packed));\ \ #define HCI_EV_LE_META 0x3e\ struct hci_ev_le_meta \{\ uint8_t subevent;\ \} __attribute__((packed));\ \ #define HCI_EV_LE_CONN_COMPLETE 0x01\ struct hci_ev_le_conn_complete \{\ uint8_t status;\ uint16_t handle;\ uint8_t role;\ uint8_t bdaddr_type;\ bdaddr_t bdaddr;\ uint16_t interval;\ uint16_t latency;\ uint16_t supervision_timeout;\ uint8_t clk_accurancy;\ \} __attribute__((packed));\ \ struct hci_dev_req \{\ uint16_t dev_id;\ uint32_t dev_opt;\ \};\ \ struct vhci_vendor_pkt \{\ uint8_t type;\ uint8_t opcode;\ uint16_t id;\ \};\ \ #define HCIDEVUP _IOW('H', 201, int)\ #define HCISETSCAN _IOW('H', 221, int)\ \ static int vhci_fd = -1;\ \ static void rfkill_unblock_all()\ \{\ int fd = open("/dev/rfkill", O_WRONLY);\ if (fd < 0)\ exit(1);\ struct rfkill_event event = \{0\};\ event.idx = 0;\ event.type = RFKILL_TYPE_ALL;\ event.op = RFKILL_OP_CHANGE_ALL;\ event.soft = 0;\ event.hard = 0;\ if (write(fd, &event, sizeof(event)) < 0)\ exit(1);\ close(fd);\ \}\ \ static void hci_send_event_packet(int fd, uint8_t evt, void* data, size_t data_len)\ \{\ struct iovec iv[3];\ struct hci_event_hdr hdr;\ hdr.evt = evt;\ hdr.plen = data_len;\ uint8_t type = HCI_EVENT_PKT;\ iv[0].iov_base = &type;\ iv[0].iov_len = sizeof(type);\ iv[1].iov_base = &hdr;\ iv[1].iov_len = sizeof(hdr);\ iv[2].iov_base = data;\ iv[2].iov_len = data_len;\ if (writev(fd, iv, sizeof(iv) / sizeof(struct iovec)) < 0)\ exit(1);\ \}\ \ static void hci_send_event_cmd_complete(int fd, uint16_t opcode, void* data, size_t data_len)\ \{\ struct iovec iv[4];\ struct hci_event_hdr hdr;\ hdr.evt = HCI_EV_CMD_COMPLETE;\ hdr.plen = sizeof(struct hci_ev_cmd_complete) + data_len;\ struct hci_ev_cmd_complete evt_hdr;\ evt_hdr.ncmd = 1;\ evt_hdr.opcode = opcode;\ uint8_t type = HCI_EVENT_PKT;\ iv[0].iov_base = &type;\ iv[0].iov_len = sizeof(type);\ iv[1].iov_base = &hdr;\ iv[1].iov_len = sizeof(hdr);\ iv[2].iov_base = &evt_hdr;\ iv[2].iov_len = sizeof(evt_hdr);\ iv[3].iov_base = data;\ iv[3].iov_len = data_len;\ if (writev(fd, iv, sizeof(iv) / sizeof(struct iovec)) < 0)\ exit(1);\ \}\ \ static bool process_command_pkt(int fd, char* buf, ssize_t buf_size)\ \{\ struct hci_command_hdr* hdr = (struct hci_command_hdr*)buf;\ if (buf_size < (ssize_t)sizeof(struct hci_command_hdr) ||\ hdr->plen != buf_size - sizeof(struct hci_command_hdr))\ exit(1);\ switch (hdr->opcode) \{\ case HCI_OP_WRITE_SCAN_ENABLE: \{\ uint8_t status = 0;\ hci_send_event_cmd_complete(fd, hdr->opcode, &status, sizeof(status));\ return true;\ \}\ case HCI_OP_READ_BD_ADDR: \{\ struct hci_rp_read_bd_addr rp = \{0\};\ rp.status = 0;\ memset(&rp.bdaddr, 0xaa, 6);\ hci_send_event_cmd_complete(fd, hdr->opcode, &rp, sizeof(rp));\ return false;\ \}\ case HCI_OP_READ_BUFFER_SIZE: \{\ struct hci_rp_read_buffer_size rp = \{0\};\ rp.status = 0;\ rp.acl_mtu = 1021;\ rp.sco_mtu = 96;\ rp.acl_max_pkt = 4;\ rp.sco_max_pkt = 6;\ hci_send_event_cmd_complete(fd, hdr->opcode, &rp, sizeof(rp));\ return false;\ \}\ \}\ char dummy[0xf9] = \{0\};\ hci_send_event_cmd_complete(fd, hdr->opcode, dummy, sizeof(dummy));\ return false;\ \}\ \ static void* event_thread(void* arg)\ \{\ while (1) \{\ char buf[1024] = \{0\};\ ssize_t buf_size = read(vhci_fd, buf, sizeof(buf));\ if (buf_size < 0)\ exit(1);\ if (buf_size > 0 && buf[0] == HCI_COMMAND_PKT) \{\ if (process_command_pkt(vhci_fd, buf + 1, buf_size - 1))\ break;\ \}\ \}\ return NULL;\ \}\ #define HCI_HANDLE_1 200\ #define HCI_HANDLE_2 201\ \ static void initialize_vhci()\ \{\ int hci_sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);\ if (hci_sock < 0)\ exit(1);\ vhci_fd = open("/dev/vhci", O_RDWR);\ if (vhci_fd == -1)\ exit(1);\ const int kVhciFd = 202;\ if (dup2(vhci_fd, kVhciFd) < 0)\ exit(1);\ close(vhci_fd);\ vhci_fd = kVhciFd;\ struct vhci_vendor_pkt vendor_pkt;\ if (read(vhci_fd, &vendor_pkt, sizeof(vendor_pkt)) != sizeof(vendor_pkt))\ exit(1);\ if (vendor_pkt.type != HCI_VENDOR_PKT)\ exit(1);\ pthread_t th;\ if (pthread_create(&th, NULL, event_thread, NULL))\ exit(1);\ int ret = ioctl(hci_sock, HCIDEVUP, vendor_pkt.id);\ if (ret) \{\ if (errno == ERFKILL) \{\ rfkill_unblock_all();\ ret = ioctl(hci_sock, HCIDEVUP, vendor_pkt.id);\ \}\ if (ret && errno != EALREADY)\ exit(1);\ \}\ struct hci_dev_req dr = \{0\};\ dr.dev_id = vendor_pkt.id;\ dr.dev_opt = SCAN_PAGE;\ if (ioctl(hci_sock, HCISETSCAN, &dr))\ exit(1);\ struct hci_ev_conn_request request;\ memset(&request, 0, sizeof(request));\ memset(&request.bdaddr, 0xaa, 6);\ *(uint8_t*)&request.bdaddr.b[5] = 0x10;\ request.link_type = ACL_LINK;\ hci_send_event_packet(vhci_fd, HCI_EV_CONN_REQUEST, &request, sizeof(request));\ struct hci_ev_conn_complete complete;\ memset(&complete, 0, sizeof(complete));\ complete.status = 0;\ complete.handle = HCI_HANDLE_1;\ memset(&complete.bdaddr, 0xaa, 6);\ *(uint8_t*)&complete.bdaddr.b[5] = 0x10;\ complete.link_type = ACL_LINK;\ complete.encr_mode = 0;\ hci_send_event_packet(vhci_fd, HCI_EV_CONN_COMPLETE, &complete, sizeof(complete));\ struct hci_ev_remote_features features;\ memset(&features, 0, sizeof(features));\ features.status = 0;\ features.handle = HCI_HANDLE_1;\ hci_send_event_packet(vhci_fd, HCI_EV_REMOTE_FEATURES, &features, sizeof(features));\ struct \{\ struct hci_ev_le_meta le_meta;\ struct hci_ev_le_conn_complete le_conn;\ \} le_conn;\ memset(&le_conn, 0, sizeof(le_conn));\ le_conn.le_meta.subevent = HCI_EV_LE_CONN_COMPLETE;\ memset(&le_conn.le_conn.bdaddr, 0xaa, 6);\ *(uint8_t*)&le_conn.le_conn.bdaddr.b[5] = 0x11;\ le_conn.le_conn.role = 1;\ le_conn.le_conn.handle = HCI_HANDLE_2;\ hci_send_event_packet(vhci_fd, HCI_EV_LE_META, &le_conn, sizeof(le_conn));\ pthread_join(th, NULL);\ close(hci_sock);\ \}\ \ static void setup_common()\ \{\ if (mount(0, "/sys/fs/fuse/connections", "fusectl", 0, 0)) \{\ \}\ \}\ \ static void setup_binderfs()\ \{\ if (mkdir("/dev/binderfs", 0777)) \{\ \}\ if (mount("binder", "/dev/binderfs", "binder", 0, NULL)) \{\ \}\ if (symlink("/dev/binderfs", "./binderfs")) \{\ \}\ \}\ \ static void loop();\ \ static void sandbox_common()\ \{\ prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);\ setsid();\ struct rlimit rlim;\ rlim.rlim_cur = rlim.rlim_max = (200 << 20);\ setrlimit(RLIMIT_AS, &rlim);\ rlim.rlim_cur = rlim.rlim_max = 32 << 20;\ setrlimit(RLIMIT_MEMLOCK, &rlim);\ rlim.rlim_cur = rlim.rlim_max = 136 << 20;\ setrlimit(RLIMIT_FSIZE, &rlim);\ rlim.rlim_cur = rlim.rlim_max = 1 << 20;\ setrlimit(RLIMIT_STACK, &rlim);\ rlim.rlim_cur = rlim.rlim_max = 0;\ setrlimit(RLIMIT_CORE, &rlim);\ rlim.rlim_cur = rlim.rlim_max = 256;\ setrlimit(RLIMIT_NOFILE, &rlim);\ if (unshare(CLONE_NEWNS)) \{\ \}\ if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL)) \{\ \}\ if (unshare(CLONE_NEWIPC)) \{\ \}\ if (unshare(0x02000000)) \{\ \}\ if (unshare(CLONE_NEWUTS)) \{\ \}\ if (unshare(CLONE_SYSVSEM)) \{\ \}\ typedef struct \{\ const char* name;\ const char* value;\ \} sysctl_t;\ static const sysctl_t sysctls[] = \{\ \{"/proc/sys/kernel/shmmax", "16777216"\},\ \{"/proc/sys/kernel/shmall", "536870912"\},\ \{"/proc/sys/kernel/shmmni", "1024"\},\ \{"/proc/sys/kernel/msgmax", "8192"\},\ \{"/proc/sys/kernel/msgmni", "1024"\},\ \{"/proc/sys/kernel/msgmnb", "1024"\},\ \{"/proc/sys/kernel/sem", "1024 1048576 500 1024"\},\ \};\ unsigned i;\ for (i = 0; i < sizeof(sysctls) / sizeof(sysctls[0]); i++)\ write_file(sysctls[i].name, sysctls[i].value);\ \}\ \ static int wait_for_loop(int pid)\ \{\ if (pid < 0)\ exit(1);\ int status = 0;\ while (waitpid(-1, &status, __WALL) != pid) \{\ \}\ return WEXITSTATUS(status);\ \}\ \ static void drop_caps(void)\ \{\ struct __user_cap_header_struct cap_hdr = \{\};\ struct __user_cap_data_struct cap_data[2] = \{\};\ cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;\ cap_hdr.pid = getpid();\ if (syscall(SYS_capget, &cap_hdr, &cap_data))\ exit(1);\ const int drop = (1 << CAP_SYS_PTRACE) | (1 << CAP_SYS_NICE);\ cap_data[0].effective &= ~drop;\ cap_data[0].permitted &= ~drop;\ cap_data[0].inheritable &= ~drop;\ if (syscall(SYS_capset, &cap_hdr, &cap_data))\ exit(1);\ \}\ \ static int do_sandbox_none(void)\ \{\ if (unshare(CLONE_NEWPID)) \{\ \}\ int pid = fork();\ if (pid != 0)\ return wait_for_loop(pid);\ setup_common();\ initialize_vhci();\ sandbox_common();\ drop_caps();\ initialize_netdevices_init();\ if (unshare(CLONE_NEWNET)) \{\ \}\ initialize_netdevices();\ setup_binderfs();\ loop();\ exit(1);\ \}\ \ static void close_fds()\ \{\ for (int fd = 3; fd < MAX_FDS; fd++)\ close(fd);\ \}\ \ static void setup_binfmt_misc()\ \{\ if (mount(0, "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, 0)) \{\ \}\ write_file("/proc/sys/fs/binfmt_misc/register", ":syz0:M:0:\\x01::./file0:");\ write_file("/proc/sys/fs/binfmt_misc/register", ":syz1:M:1:\\x02::./file0:POC");\ \}\ \ static void setup_sysctl()\ \{\ char mypid[32];\ snprintf(mypid, sizeof(mypid), "%d", getpid());\ struct \{\ const char* name;\ const char* data;\ \} files[] = \{\ \{"/sys/kernel/debug/x86/nmi_longest_ns", "10000000000"\},\ \{"/proc/sys/kernel/hung_task_check_interval_secs", "20"\},\ \{"/proc/sys/net/core/bpf_jit_kallsyms", "1"\},\ \{"/proc/sys/net/core/bpf_jit_harden", "0"\},\ \{"/proc/sys/kernel/kptr_restrict", "0"\},\ \{"/proc/sys/kernel/softlockup_all_cpu_backtrace", "1"\},\ \{"/proc/sys/fs/mount-max", "100"\},\ \{"/proc/sys/vm/oom_dump_tasks", "0"\},\ \{"/proc/sys/debug/exception-trace", "0"\},\ \{"/proc/sys/kernel/printk", "7 4 1 3"\},\ \{"/proc/sys/net/ipv4/ping_group_range", "0 65535"\},\ \{"/proc/sys/kernel/keys/gc_delay", "1"\},\ \{"/proc/sys/vm/oom_kill_allocating_task", "1"\},\ \{"/proc/sys/kernel/ctrl-alt-del", "0"\},\ \{"/proc/sys/kernel/cad_pid", mypid\},\ \};\ for (size_t i = 0; i < sizeof(files) / sizeof(files[0]); i++) \{\ if (!write_file(files[i].name, files[i].data))\ printf("write to %s failed: %s\\n", files[i].name, strerror(errno));\ \}\ \}\ \ uint64_t r[1] = \{0xffffffffffffffff\};\ \ void loop(void)\ \{\ intptr_t res = 0;\ res = syscall(__NR_socket, 2ul, 2ul, 0x73);\ if (res != -1)\ r[0] = res;\ memcpy((void*)0x20000040, "filter\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000\\000", 32);\ *(uint32_t*)0x20000060 = 6;\ *(uint32_t*)0x20000064 = 0;\ *(uint32_t*)0x20000068 = 0x90;\ *(uint64_t*)0x20000070 = 0;\ *(uint64_t*)0x20000078 = 0x20000400;\ *(uint64_t*)0x20000080 = 0x20000430;\ *(uint64_t*)0x20000088 = 0;\ *(uint64_t*)0x20000090 = 0;\ *(uint64_t*)0x20000098 = 0;\ *(uint32_t*)0x200000a0 = 0;\ *(uint64_t*)0x200000a8 = 0;\ *(uint64_t*)0x200000b0 = 0x20000400;\ *(uint32_t*)0x20000400 = 0;\ memset((void*)0x20000404, 0, 32);\ *(uint32_t*)0x20000424 = 0;\ *(uint32_t*)0x20000428 = -1;\ *(uint32_t*)0x2000042c = 0;\ *(uint32_t*)0x20000430 = 0;\ memset((void*)0x20000434, 0, 32);\ *(uint32_t*)0x20000454 = 0;\ *(uint32_t*)0x20000458 = -1;\ *(uint32_t*)0x2000045c = 0;\ *(uint32_t*)0x20000460 = 0;\ memset((void*)0x20000464, 0, 32);\ *(uint32_t*)0x20000484 = 0;\ *(uint32_t*)0x20000488 = 0xfffffffc;\ *(uint32_t*)0x2000048c = 0;\ syscall(__NR_setsockopt, r[0], 0, 0x80, 0x20000040ul, 0x108ul);\ close_fds();\ \}\ int main(void)\ \{\ syscall(__NR_mmap, 0x1ffff000ul, 0x1000ul, 0ul, 0x32ul, -1, 0ul);\ syscall(__NR_mmap, 0x20000000ul, 0x1000000ul, 7ul, 0x32ul, -1, 0ul);\ syscall(__NR_mmap, 0x21000000ul, 0x1000ul, 0ul, 0x32ul, -1, 0ul);\ setup_sysctl();\ setup_binfmt_misc();\ do_sandbox_none();\ return 0;\ \}\ }