aboutgitcodebugslistschat
path: root/conf.c
diff options
context:
space:
mode:
authorStefano Brivio <sbrivio@redhat.com>2021-10-11 12:01:31 +0200
committerStefano Brivio <sbrivio@redhat.com>2021-10-14 13:15:12 +0200
commit675174d4ba255383b213437e29b617d8f55dbc69 (patch)
tree7add0cf70e595028f9ca9485eb8e139d3d652bb6 /conf.c
parentdcd3605d14aba011fa6c2f4596cb7494f64d2b93 (diff)
downloadpasst-675174d4ba255383b213437e29b617d8f55dbc69.tar
passt-675174d4ba255383b213437e29b617d8f55dbc69.tar.gz
passt-675174d4ba255383b213437e29b617d8f55dbc69.tar.bz2
passt-675174d4ba255383b213437e29b617d8f55dbc69.tar.lz
passt-675174d4ba255383b213437e29b617d8f55dbc69.tar.xz
passt-675174d4ba255383b213437e29b617d8f55dbc69.tar.zst
passt-675174d4ba255383b213437e29b617d8f55dbc69.zip
conf, tap: Split netlink and pasta functions, allow interface configuration
Move netlink routines to their own file, and use netlink to configure or fetch all the information we need, except for the TUNSETIFF ioctl. Move pasta-specific functions to their own file as well, add parameters and calls to configure the tap interface in the namespace. Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Diffstat (limited to 'conf.c')
-rw-r--r--conf.c448
1 files changed, 132 insertions, 316 deletions
diff --git a/conf.c b/conf.c
index e020417..6399fbb 100644
--- a/conf.c
+++ b/conf.c
@@ -17,7 +17,6 @@
#include <getopt.h>
#include <string.h>
#include <errno.h>
-#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -38,6 +37,8 @@
#include "passt.h"
#include "udp.h"
#include "tcp.h"
+#include "netlink.h"
+#include "pasta.h"
/**
* get_bound_ports() - Get maps of ports with bound sockets
@@ -267,301 +268,6 @@ overlap:
}
/**
- * nl_req() - Send netlink request and read response, doesn't return on failure
- * @buf: Buffer for response (BUFSIZ long)
- * @req: Request with netlink header
- * @len: Request length
- */
-static void nl_req(char *buf, void *req, ssize_t len)
-{
- int s = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE), v = 1;
- struct sockaddr_nl addr = { .nl_family = AF_NETLINK, };
-
- if (s < 0 ||
- setsockopt(s, SOL_NETLINK, NETLINK_GET_STRICT_CHK, &v, sizeof(v)) ||
- bind(s, (struct sockaddr *)&addr, sizeof(addr)) ||
- (send(s, req, len, 0) < len) ||
- (recv(s, buf, BUFSIZ, 0) < 0)) {
- perror("netlink recv");
- exit(EXIT_FAILURE);
- }
-
- close(s);
-}
-
-/**
- * get_routes() - Get default route and fill in routable interface name
- * @c: Execution context
- */
-static void get_routes(struct ctx *c)
-{
- struct { struct nlmsghdr nlh; struct rtmsg rtm; } req = {
- .nlh.nlmsg_type = RTM_GETROUTE,
- .nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP | NLM_F_EXCL,
- .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
- .nlh.nlmsg_seq = 1,
- .rtm.rtm_family = AF_INET,
- .rtm.rtm_table = RT_TABLE_MAIN,
- .rtm.rtm_scope = RT_SCOPE_UNIVERSE,
- .rtm.rtm_type = RTN_UNICAST,
- };
- char ifn[IFNAMSIZ], buf[BUFSIZ];
- struct nlmsghdr *nh;
- struct rtattr *rta;
- struct rtmsg *rtm;
- int n, na, v4, v6;
-
- if (!c->v4 && !c->v6)
- v4 = v6 = -1;
- else
- v6 = -!(v4 = -c->v4);
-
-v6:
- nl_req(buf, &req, sizeof(req));
- nh = (struct nlmsghdr *)buf;
-
- for ( ; NLMSG_OK(nh, n); nh = NLMSG_NEXT(nh, n)) {
- rtm = (struct rtmsg *)NLMSG_DATA(nh);
-
- if (rtm->rtm_dst_len ||
- (rtm->rtm_family != AF_INET && rtm->rtm_family != AF_INET6))
- continue;
-
- /* Filter on interface only if already given */
- if (*c->ifn) {
- *ifn = 0;
- for (rta = (struct rtattr *)RTM_RTA(rtm),
- na = RTM_PAYLOAD(nh);
- RTA_OK(rta, na); rta = RTA_NEXT(rta, na)) {
- if (rta->rta_type != RTA_OIF)
- continue;
-
- if_indextoname(*(unsigned *)RTA_DATA(rta), ifn);
- break;
- }
-
- if (strcmp(ifn, c->ifn))
- goto next;
- }
-
- for (rta = (struct rtattr *)RTM_RTA(rtm), na = RTM_PAYLOAD(nh);
- RTA_OK(rta, na); rta = RTA_NEXT(rta, na)) {
- if (!*c->ifn && rta->rta_type == RTA_OIF)
- if_indextoname(*(unsigned *)RTA_DATA(rta), ifn);
-
- if (v4 && rta->rta_type == RTA_GATEWAY &&
- rtm->rtm_family == AF_INET) {
- if (!c->gw4) {
- memcpy(&c->gw4, RTA_DATA(rta),
- sizeof(c->gw4));
- }
- v4 = 1;
- }
-
- if (v6 && rta->rta_type == RTA_GATEWAY &&
- rtm->rtm_family == AF_INET6) {
- if (IN6_IS_ADDR_UNSPECIFIED(&c->gw6)) {
- memcpy(&c->gw6, RTA_DATA(rta),
- sizeof(c->gw6));
- }
- v6 = 1;
- }
- }
-
-next:
- if (nh->nlmsg_type == NLMSG_DONE)
- break;
- }
-
- if (v6 < 0 && req.rtm.rtm_family == AF_INET) {
- req.rtm.rtm_family = AF_INET6;
- req.nlh.nlmsg_seq++;
- goto v6;
- } else if (v6 < 0) {
- v6 = 0;
- }
-
- if ((v4 <= 0 && v6 <= 0) || (!*c->ifn && !*ifn)) {
- err("No routing information");
- exit(EXIT_FAILURE);
- }
-
- if (!*c->ifn)
- strncpy(c->ifn, ifn, IFNAMSIZ);
- c->v4 = v4;
- c->v6 = v6;
-}
-
-/**
- * get_l3_addrs() - Fetch IP addresses of external routable interface
- * @c: Execution context
- */
-static void get_l3_addrs(struct ctx *c)
-{
- struct { struct nlmsghdr nlh; struct ifaddrmsg ifa; } req = {
- .nlh.nlmsg_type = RTM_GETADDR,
- .nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
- .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
- .nlh.nlmsg_seq = 1,
- .ifa.ifa_family = AF_INET,
- .ifa.ifa_index = if_nametoindex(c->ifn),
- };
- struct ifaddrmsg *ifa;
- struct nlmsghdr *nh;
- struct rtattr *rta;
- int n, na, v4, v6;
- char buf[BUFSIZ];
-
- if (c->v4) {
- v4 = -1;
- if ((c->addr4_seen = c->addr4))
- v4 = 1;
- }
-
- if (c->v6) {
- v6 = -2;
- if (!IN6_IS_ADDR_UNSPECIFIED(&c->addr6)) {
- memcpy(&c->addr6_seen, &c->addr6, sizeof(c->addr6));
- memcpy(&c->addr6_ll_seen, &c->addr6, sizeof(c->addr6));
- v6 = -1;
- }
- }
-
-next_v:
- if (v4 < 0)
- req.ifa.ifa_family = AF_INET;
- else if (v6 < 0)
- req.ifa.ifa_family = AF_INET6;
- else
- goto mask_only;
-
- nl_req(buf, &req, sizeof(req));
- nh = (struct nlmsghdr *)buf;
-
- for ( ; NLMSG_OK(nh, n); nh = NLMSG_NEXT(nh, n)) {
- if (nh->nlmsg_type != RTM_NEWADDR)
- goto next;
-
- ifa = (struct ifaddrmsg *)NLMSG_DATA(nh);
-
- for (rta = (struct rtattr *)IFA_RTA(ifa), na = RTM_PAYLOAD(nh);
- RTA_OK(rta, na); rta = RTA_NEXT(rta, na)) {
- if (rta->rta_type != IFA_ADDRESS)
- continue;
-
- if (v4 < 0) {
- memcpy(&c->addr4, RTA_DATA(rta),
- sizeof(c->addr4));
- memcpy(&c->addr4_seen, RTA_DATA(rta),
- sizeof(c->addr4_seen));
- v4 = 1;
- } else if (v6 < 0) {
- if (v6 == -2 &&
- ifa->ifa_scope == RT_SCOPE_UNIVERSE) {
- memcpy(&c->addr6, RTA_DATA(rta),
- sizeof(c->addr6));
- memcpy(&c->addr6_seen, RTA_DATA(rta),
- sizeof(c->addr6_seen));
- memcpy(&c->addr6_ll_seen, RTA_DATA(rta),
- sizeof(c->addr6_ll_seen));
- } else if (ifa->ifa_scope == RT_SCOPE_LINK) {
- memcpy(&c->addr6_ll, RTA_DATA(rta),
- sizeof(c->addr6_ll));
- }
- if (!IN6_IS_ADDR_UNSPECIFIED(&c->addr6) &&
- !IN6_IS_ADDR_UNSPECIFIED(&c->addr6_ll))
- v6 = 1;
- }
- }
-next:
- if (nh->nlmsg_type == NLMSG_DONE)
- break;
- }
-
- if (v4 >= 0 && v6 < 0)
- goto next_v;
-
- if (v4 < c->v4 || v6 < c->v6)
- goto out;
-
-mask_only:
- if (v4 && !c->mask4) {
- if (IN_CLASSA(ntohl(c->addr4)))
- c->mask4 = htonl(IN_CLASSA_NET);
- else if (IN_CLASSB(ntohl(c->addr4)))
- c->mask4 = htonl(IN_CLASSB_NET);
- else if (IN_CLASSC(ntohl(c->addr4)))
- c->mask4 = htonl(IN_CLASSC_NET);
- else
- c->mask4 = 0xffffffff;
- }
-
- return;
-out:
- err("Couldn't get addresses for routable interface");
- exit(EXIT_FAILURE);
-}
-
-/**
- * get_l2_addr() - Fetch hardware addresses of external routable interface
- * @c: Execution context
- */
-static void get_l2_addr(struct ctx *c)
-{
- struct { struct nlmsghdr nlh; struct ifinfomsg ifi; } req = {
- .nlh.nlmsg_type = RTM_GETLINK,
- .nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP_FILTERED,
- .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
- .nlh.nlmsg_seq = 1,
- .ifi.ifi_family = AF_UNSPEC,
- .ifi.ifi_index = if_nametoindex(c->ifn),
- };
- struct ifinfomsg *ifi;
- struct nlmsghdr *nh;
- struct rtattr *rta;
- char buf[BUFSIZ];
- int n, na;
-
- if (memcmp(c->mac, ((uint8_t [ETH_ALEN]){ 0 }), ETH_ALEN))
- goto mac_guest;
-
- nl_req(buf, &req, sizeof(req));
- nh = (struct nlmsghdr *)buf;
-
- for ( ; NLMSG_OK(nh, n); nh = NLMSG_NEXT(nh, n)) {
- if (nh->nlmsg_type != RTM_NEWLINK)
- goto next;
-
- ifi = (struct ifinfomsg *)NLMSG_DATA(nh);
-
- for (rta = (struct rtattr *)IFLA_RTA(ifi), na = RTM_PAYLOAD(nh);
- RTA_OK(rta, na); rta = RTA_NEXT(rta, na)) {
- if (rta->rta_type != IFLA_ADDRESS)
- continue;
-
- memcpy(c->mac, RTA_DATA(rta), ETH_ALEN);
- break;
- }
-next:
- if (nh->nlmsg_type == NLMSG_DONE)
- break;
- }
-
- if (!memcmp(c->mac, ((uint8_t [ETH_ALEN]){ 0 }), ETH_ALEN))
- goto out;
-
-mac_guest:
- if (memcmp(c->mac_guest, ((uint8_t [ETH_ALEN]){ 0 }), ETH_ALEN))
- memset(&c->mac_guest, 0xff, sizeof(c->mac_guest));
-
- return;
-
-out:
- err("Couldn't get hardware address for routable interface");
- exit(EXIT_FAILURE);
-}
-
-/**
* get_dns() - Get nameserver addresses from local /etc/resolv.conf
* @c: Execution context
*/
@@ -731,6 +437,91 @@ static int conf_ns_opt(struct ctx *c,
}
/**
+ * conf_ip() - Verify or detect IPv4/IPv6 support, get relevant addresses
+ * @c: Execution context
+ */
+static void conf_ip(struct ctx *c)
+{
+ int v4, v6;
+
+ if (c->v4) {
+ c->v4 = IP_VERSION_ENABLED;
+ v4 = IP_VERSION_PROBE;
+ v6 = c->v6 = IP_VERSION_DISABLED;
+ } else if (c->v6) {
+ c->v6 = IP_VERSION_ENABLED;
+ v6 = IP_VERSION_PROBE;
+ v4 = c->v4 = IP_VERSION_DISABLED;
+ } else {
+ c->v4 = c->v6 = IP_VERSION_ENABLED;
+ v4 = v6 = IP_VERSION_PROBE;
+ }
+
+ if (!c->ifi)
+ c->ifi = nl_get_ext_if(&v4, &v6);
+
+ if (v4 != IP_VERSION_DISABLED) {
+ if (!c->gw4)
+ nl_route(0, c->ifi, AF_INET, &c->gw4);
+
+ if (!c->addr4) {
+ nl_addr(0, c->ifi, AF_INET, &c->addr4, 0, NULL);
+ if (!c->mask4) {
+ if (IN_CLASSA(ntohl(c->addr4)))
+ c->mask4 = htonl(IN_CLASSA_NET);
+ else if (IN_CLASSB(ntohl(c->addr4)))
+ c->mask4 = htonl(IN_CLASSB_NET);
+ else if (IN_CLASSC(ntohl(c->addr4)))
+ c->mask4 = htonl(IN_CLASSC_NET);
+ else
+ c->mask4 = 0xffffffff;
+ }
+ }
+
+ memcpy(&c->addr4_seen, &c->addr4, sizeof(c->addr4_seen));
+
+ if (!memcmp(c->mac, MAC_ZERO, ETH_ALEN))
+ nl_link(0, c->ifi, c->mac, 0);
+ }
+
+ if (c->mode == MODE_PASST)
+ memset(&c->mac_guest, 0xff, sizeof(c->mac_guest));
+
+ if (v6 != IP_VERSION_DISABLED) {
+ if (IN6_IS_ADDR_UNSPECIFIED(&c->gw6))
+ nl_route(0, c->ifi, AF_INET6, &c->gw6);
+
+ nl_addr(0, c->ifi, AF_INET6,
+ IN6_IS_ADDR_UNSPECIFIED(&c->addr6) ? &c->addr6 : NULL,
+ 0, &c->addr6_ll);
+
+ memcpy(&c->addr6_seen, &c->addr6, sizeof(c->addr4_seen));
+ memcpy(&c->addr6_ll_seen, &c->addr6, sizeof(c->addr4_seen));
+ }
+
+ if (!c->gw4 || !c->addr4 ||
+ !memcmp(c->mac, ((uint8_t [ETH_ALEN]){ 0 }), ETH_ALEN))
+ v4 = IP_VERSION_DISABLED;
+ else
+ v4 = IP_VERSION_ENABLED;
+
+ if (IN6_IS_ADDR_UNSPECIFIED(&c->gw6) ||
+ IN6_IS_ADDR_UNSPECIFIED(&c->addr6) ||
+ IN6_IS_ADDR_UNSPECIFIED(&c->addr6_ll))
+ v6 = IP_VERSION_DISABLED;
+ else
+ v6 = IP_VERSION_ENABLED;
+
+ if ((v4 == IP_VERSION_DISABLED) && (v6 == IP_VERSION_DISABLED)) {
+ err("External interface not usable");
+ exit(EXIT_FAILURE);
+ }
+
+ c->v4 = v4;
+ c->v6 = v6;
+}
+
+/**
* usage() - Print usage and exit
* @name: Executable name
*/
@@ -868,20 +659,22 @@ pasta_opts:
info( " implied if PATH or NAME are given without --userns");
info( " --nsrun-dir Directory for nsfs mountpoints");
info( " default: " NETNS_RUN_DIR);
+ info( " --config-net Configure tap interface in namespace");
+ info( " --ns-mac-addr ADDR Set MAC address on tap interface");
exit(EXIT_FAILURE);
}
void conf_print(struct ctx *c)
{
- char buf6[INET6_ADDRSTRLEN], buf4[INET_ADDRSTRLEN];
+ char buf6[INET6_ADDRSTRLEN], buf4[INET_ADDRSTRLEN], ifn[IFNAMSIZ];
int i;
if (c->mode == MODE_PASTA) {
info("Outbound interface: %s, namespace interface: %s",
- c->ifn, c->pasta_ifn);
+ if_indextoname(c->ifi, ifn), c->pasta_ifn);
} else {
- info("Outbound interface: %s", c->ifn);
+ info("Outbound interface: %s", if_indextoname(c->ifi, ifn));
}
if (c->v4) {
@@ -991,6 +784,8 @@ void conf(struct ctx *c, int argc, char **argv)
{"userns", required_argument, NULL, 2 },
{"netns-only", no_argument, &c->netns_only, 1 },
{"nsrun-dir", required_argument, NULL, 3 },
+ {"config-net", no_argument, &c->pasta_conf_ns, 1 },
+ {"ns-mac-addr", required_argument, NULL, 4 },
{ 0 },
};
struct get_bound_ports_ns_arg ns_ports_arg = { .c = c };
@@ -1051,6 +846,22 @@ void conf(struct ctx *c, int argc, char **argv)
usage(argv[0]);
}
break;
+ case 4:
+ if (c->mode != MODE_PASTA) {
+ err("--ns-mac-addr is for pasta mode only");
+ usage(argv[0]);
+ }
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ errno = 0;
+ b = strtol(optarg + i * 3, NULL, 16);
+ if (b < 0 || b > UCHAR_MAX || errno) {
+ err("Invalid MAC address: %s", optarg);
+ usage(argv[0]);
+ }
+ c->mac_guest[i] = b;
+ }
+ break;
case 'd':
if (c->debug) {
err("Multiple --debug options given");
@@ -1217,12 +1028,16 @@ void conf(struct ctx *c, int argc, char **argv)
usage(argv[0]);
break;
case 'i':
- if (*c->ifn) {
+ if (c->ifi) {
err("Redundant interface: %s", optarg);
usage(argv[0]);
}
- strncpy(c->ifn, optarg, IFNAMSIZ - 1);
+ if (!(c->ifi = if_nametoindex(optarg))) {
+ err("Invalid interface name %s: %s", optarg,
+ strerror(errno));
+ usage(argv[0]);
+ }
break;
case 'D':
if (c->no_dns ||
@@ -1320,25 +1135,26 @@ void conf(struct ctx *c, int argc, char **argv)
usage(argv[0]);
}
- if (c->v4 || c->v6) {
- if (!c->v4)
- c->no_dhcp = 1;
+ if (c->mode == MODE_PASTA && !c->pasta_netns_fd)
+ pasta_start_ns(c);
- if (!c->v6) {
- c->no_ndp = 1;
- c->no_dhcpv6 = 1;
- }
+ if (nl_sock_init(c)) {
+ err("Failed to get netlink socket");
+ exit(EXIT_FAILURE);
}
- if (!c->mtu) {
- c->mtu = (ETH_MAX_MTU - ETH_HLEN) /
- sizeof(uint32_t) * sizeof(uint32_t);
+ conf_ip(c);
+
+ if (!c->v4)
+ c->no_dhcp = 1;
+
+ if (!c->v6) {
+ c->no_ndp = 1;
+ c->no_dhcpv6 = 1;
}
- get_routes(c);
- get_l3_addrs(c);
- if (c->v4)
- get_l2_addr(c);
+ if (!c->mtu)
+ c->mtu = ROUND_DOWN(ETH_MAX_MTU - ETH_HLEN, sizeof(uint32_t));
if (c->mode == MODE_PASTA && dns4 == c->dns4 && dns6 == c->dns6)
c->no_dns = 1;
@@ -1347,7 +1163,7 @@ void conf(struct ctx *c, int argc, char **argv)
get_dns(c);
if (!*c->pasta_ifn)
- strncpy(c->pasta_ifn, c->ifn, IFNAMSIZ);
+ if_indextoname(c->ifi, c->pasta_ifn);
#ifdef PASST_LEGACY_NO_OPTIONS
if (c->mode == MODE_PASST) {