From b9d85cdd64e28353138ade5e6ea69d82d8eae390 Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Fri, 8 Mar 2019 19:52:35 +0200 Subject: [PATCH 01/35] Add addr to interface as CIDR --- src/tuntap_if.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tuntap_if.c b/src/tuntap_if.c index 5677a9d..817deac 100644 --- a/src/tuntap_if.c +++ b/src/tuntap_if.c @@ -6,6 +6,7 @@ static int tun_fd; static char* dev; char *tapaddr = "10.0.0.5"; +char *cidr = "10.0.0.5/24"; char *taproute = "10.0.0.0/24"; static int set_if_route(char *dev, char *cidr) @@ -83,7 +84,7 @@ void tun_init() print_err("ERROR when setting route for if\n"); } - if (set_if_address(dev, tapaddr) != 0) { + if (set_if_address(dev, cidr) != 0) { print_err("ERROR when setting addr for if\n"); } } From b39024388cec087a7792314b926a8cfdcb9c48f4 Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Fri, 8 Mar 2019 19:53:31 +0200 Subject: [PATCH 02/35] Add exit_with_error macro --- include/utils.h | 3 +++ src/ipc.c | 37 +++++++++++++------------------------ 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/include/utils.h b/include/utils.h index f70a498..00e894c 100644 --- a/include/utils.h +++ b/include/utils.h @@ -9,6 +9,9 @@ #define print_err(str, ...) \ fprintf(stderr, str, ##__VA_ARGS__); +#define exit_with_error(en, msg) \ + do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0) + int run_cmd(char *cmd, ...); uint32_t sum_every_16bits(void *addr, int count); uint16_t checksum(void *addr, int count, int start_sum); diff --git a/src/ipc.c b/src/ipc.c index 8e149e1..714ac3e 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -476,47 +476,36 @@ void *start_ipc_listener() } if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { - perror("IPC listener UNIX socket"); - exit(EXIT_FAILURE); + exit_with_error(fd, "IPC listener UNIX socket"); } memset(&un, 0, sizeof(struct sockaddr_un)); un.sun_family = AF_UNIX; strncpy(un.sun_path, sockname, sizeof(un.sun_path) - 1); - rc = bind(fd, (const struct sockaddr *) &un, sizeof(struct sockaddr_un)); - - if (rc == -1) { - perror("IPC bind"); - exit(EXIT_FAILURE); + if ((rc = bind(fd, (const struct sockaddr *) &un, sizeof(struct sockaddr_un))) == -1) { + exit_with_error(rc, "IPC bind"); } - rc = listen(fd, 20); - - if (rc == -1) { - perror("IPC listen"); - exit(EXIT_FAILURE); + if ((rc = listen(fd, 20)) == -1) { + exit_with_error(rc, "IPC listen"); } - if (chmod(sockname, S_IRUSR | S_IWUSR | S_IXUSR | - S_IRGRP | S_IWGRP | S_IXGRP | - S_IROTH | S_IWOTH | S_IXOTH) == -1) { - perror("Chmod on lvl-ip IPC UNIX socket failed"); - exit(EXIT_FAILURE); + if ((rc = chmod(sockname, S_IRUSR | S_IWUSR | S_IXUSR | + S_IRGRP | S_IWGRP | S_IXGRP | + S_IROTH | S_IWOTH | S_IXOTH)) == -1) { + exit_with_error(rc, "Chmod on lvl-ip IPC UNIX socket failed"); } for (;;) { - datasock = accept(fd, NULL, NULL); - if (datasock == -1) { - perror("IPC accept"); - exit(EXIT_FAILURE); + if ((datasock = accept(fd, NULL, NULL)) == -1) { + exit_with_error(datasock ,"IPC accept"); } struct ipc_thread *th = ipc_alloc_thread(datasock); - if (pthread_create(&th->id, NULL, &socket_ipc_open, &th->sock) != 0) { - print_err("Error on socket thread creation\n"); - exit(1); + if ((rc = pthread_create(&th->id, NULL, &socket_ipc_open, &th->sock)) != 0) { + exit_with_error(rc, "Error on socket thread creation"); }; } From e2cb38e59163ccf0820637e84d862b638ffb6feb Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Fri, 8 Mar 2019 19:54:54 +0200 Subject: [PATCH 03/35] Make code blocks in README easier to copy --- Documentation/getting-started.md | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/Documentation/getting-started.md b/Documentation/getting-started.md index a6377d6..929e014 100644 --- a/Documentation/getting-started.md +++ b/Documentation/getting-started.md @@ -10,7 +10,7 @@ DISCLAIMER: Level-IP is not a production-ready networking stack, and does not in Standard `make` stuff. - $ make all + make all This builds `lvl-ip` itself, but also the libc wrapper and provided example applications. @@ -18,26 +18,24 @@ When building, `sudo setcap ...` probably asks super user permissions from you. Currently, `lvl-ip` also configures the tap interface through the `ip` tool. Hence, give it permissions too: - $ which ip - /usr/bin/ip - $ sudo setcap cap_net_admin=ep /usr/bin/ip + sudo setcap cap_net_admin=ep $(which ip) # Setup Level-IP uses a Linux TAP device to communicate to the outside world. In short, the tap device is initialized in the host Linux' networking stack, and `lvl-ip` can then read the L2 frames: - $ sudo mknod /dev/net/tap c 10 200 - $ sudo chmod 0666 /dev/net/tap + sudo mknod /dev/net/tap c 10 200 + sudo chmod 0666 /dev/net/tap In essence, `lvl-ip` operates as a host inside the tap device's subnet. Therefore, in order to communicate with other hosts, the tap device needs to be set in a forwarding mode: An example from my (Arch) Linux machine, where `wlp2s0` is my outgoing interface, and `tap0` is the tap device for `lvl-ip`: - $ sysctl -w net.ipv4.ip_forward=1 - $ iptables -I INPUT --source 10.0.0.0/24 -j ACCEPT - $ iptables -t nat -I POSTROUTING --out-interface wlp2s0 -j MASQUERADE - $ iptables -I FORWARD --in-interface wlp2s0 --out-interface tap0 -j ACCEPT - $ iptables -I FORWARD --in-interface tap0 --out-interface wlp2s0 -j ACCEPT + sysctl -w net.ipv4.ip_forward=1 + iptables -I INPUT --source 10.0.0.0/24 -j ACCEPT + iptables -t nat -I POSTROUTING --out-interface wlp2s0 -j MASQUERADE + iptables -I FORWARD --in-interface wlp2s0 --out-interface tap0 -j ACCEPT + iptables -I FORWARD --in-interface tap0 --out-interface wlp2s0 -j ACCEPT Now, packets coming from `lvl-ip` (10.0.0.4/24 in this case) should be NATed by the host Linux interfaces and traverse the FORWARD chain correctly to the host's outgoing gateway. @@ -47,12 +45,12 @@ See http://www.netfilter.org/documentation/HOWTO/packet-filtering-HOWTO-9.html f When you've built lvl-ip and setup your host stack to forward packets, you can try communicating to the Internet: - $ ./lvl-ip + ./lvl-ip The userspace TCP/IP stack should start. Now, first test communications with the provided applications: - $ cd tools - $ ./level-ip ../apps/curl/curl google.com 80 + cd tools + ./level-ip ../apps/curl/curl google.com 80 `./level-ip` is just a bash-script that allows `liblevelip.so` to take precedence over the libc socket API calls. From 37950a3170e4e5195e936d67ba8249798e8a655f Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Sat, 9 Mar 2019 09:53:03 +0200 Subject: [PATCH 04/35] Support NETLINK socket type in liblevelip --- tools/liblevelip.c | 18 +++++++++++++----- tools/liblevelip.h | 1 + 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/tools/liblevelip.c b/tools/liblevelip.c index e2512a2..2a742ce 100644 --- a/tools/liblevelip.c +++ b/tools/liblevelip.c @@ -59,13 +59,21 @@ static inline struct lvlip_sock *lvlip_get_sock(int fd) { static int is_socket_supported(int domain, int type, int protocol) { - if (domain != AF_INET) return 0; + int supported = 0; - if (!(type & SOCK_STREAM)) return 0; - - if (protocol != 0 && protocol != IPPROTO_TCP) return 0; + switch (domain) { + case AF_INET: + if (type & SOCK_STREAM && + protocol == IPPROTO_TCP) supported = 1; + break; + case AF_NETLINK: + if (protocol & NETLINK_SOCK_DIAG) supported = 1; + break; + default: + supported = 0; + } - return 1; + return supported; } static int init_socket(char *sockname) diff --git a/tools/liblevelip.h b/tools/liblevelip.h index 11519bd..07f6ffa 100644 --- a/tools/liblevelip.h +++ b/tools/liblevelip.h @@ -3,6 +3,7 @@ #include #include +#include #include "list.h" #include "utils.h" From 2cff64b84debaf10e00edf8609304834ed922fea Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Sat, 9 Mar 2019 18:26:01 +0200 Subject: [PATCH 05/35] Start adding AF_NETLINK socket type --- include/netlink.h | 31 ++++++ include/syshead.h | 1 + src/netlink.c | 235 ++++++++++++++++++++++++++++++++++++++++++++++ src/socket.c | 3 + 4 files changed, 270 insertions(+) create mode 100644 include/netlink.h create mode 100644 src/netlink.c diff --git a/include/netlink.h b/include/netlink.h new file mode 100644 index 0000000..8b6e146 --- /dev/null +++ b/include/netlink.h @@ -0,0 +1,31 @@ +#ifndef _NETLINK_H +#define _NETLINK_H + +#include "syshead.h" +#include "socket.h" +#include "skbuff.h" + +#ifdef DEBUG_SOCKET +#define netlink_dbg(sock, msg, ...) \ + do { \ + socket_dbg(sock, "NETLINK "msg, ##__VA_ARGS__); \ + } while (0) +#else +#define netlink_dbg(msg, th, ...) +#endif + +int netlink_create(struct socket *sock, int protocol); +int netlink_socket(struct socket *sock, int protocol); +int netlink_connect(struct socket *sock, struct sockaddr *addr, int addr_len, int flags); +int netlink_write(struct socket *sock, const void *buf, int len); +int netlink_read(struct socket *sock, void *buf, int len); +int netlink_close(struct socket *sock); +int netlink_free(struct socket *sock); +int netlink_abort(struct socket *sock); +int netlink_getpeername(struct socket *sock, struct sockaddr *restrict address, + socklen_t *restrict address_len); +int netlink_getsockname(struct socket *sock, struct sockaddr *restrict address, + socklen_t *restrict address_len); + +struct sock *netlink_lookup(struct sk_buff *skb, uint16_t sport, uint16_t dport); +#endif diff --git a/include/syshead.h b/include/syshead.h index 0f2cc23..3456dde 100644 --- a/include/syshead.h +++ b/include/syshead.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/src/netlink.c b/src/netlink.c new file mode 100644 index 0000000..d74a911 --- /dev/null +++ b/src/netlink.c @@ -0,0 +1,235 @@ +#include "syshead.h" +#include "netlink.h" +#include "socket.h" +#include "sock.h" +#include "tcp.h" +#include "wait.h" + +extern struct net_ops tcp_ops; + +static int netlink_stream_connect(struct socket *sock, const struct sockaddr *addr, + int addr_len, int flags); + +static int netlink_OPS = 1; + +struct net_family netlink = { + .create = netlink_create, +}; + +static struct sock_ops netlink_stream_ops = { + .connect = &netlink_stream_connect, + .write = &netlink_write, + .read = &netlink_read, + .close = &netlink_close, + .free = &netlink_free, + .abort = &netlink_abort, + .getpeername = &netlink_getpeername, + .getsockname = &netlink_getsockname, +}; + +static struct sock_type netlink_ops[] = { + { + .sock_ops = &netlink_stream_ops, + .net_ops = &tcp_ops, + .type = SOCK_STREAM, + .protocol = IPPROTO_TCP, + } +}; + +int netlink_create(struct socket *sock, int protocol) +{ + struct sock *sk; + struct sock_type *skt = NULL; + + for (int i = 0; i < netlink_OPS; i++) { + if (netlink_ops[i].type & sock->type) { + skt = &netlink_ops[i]; + break; + } + } + + if (!skt) { + print_err("Could not find socktype for socket\n"); + return 1; + } + + sock->ops = skt->sock_ops; + + sk = sk_alloc(skt->net_ops, protocol); + sk->protocol = protocol; + + sock_init_data(sock, sk); + + return 0; +} + +int netlink_socket(struct socket *sock, int protocol) +{ + return 0; +} + +int netlink_connect(struct socket *sock, struct sockaddr *addr, + int addr_len, int flags) +{ + return 0; +} + +static int netlink_stream_connect(struct socket *sock, const struct sockaddr *addr, + int addr_len, int flags) +{ + struct sock *sk = sock->sk; + int rc = 0; + + if (addr_len < sizeof(addr->sa_family)) { + return -EINVAL; + } + + if (addr->sa_family == AF_UNSPEC) { + sk->ops->disconnect(sk, flags); + return -EAFNOSUPPORT; + } + + switch (sock->state) { + default: + sk->err = -EINVAL; + goto out; + case SS_CONNECTED: + sk->err = -EISCONN; + goto out; + case SS_CONNECTING: + sk->err = -EALREADY; + goto out; + case SS_UNCONNECTED: + sk->err = -EISCONN; + if (sk->state != TCP_CLOSE) { + goto out; + } + + sk->ops->connect(sk, addr, addr_len, flags); + sock->state = SS_CONNECTING; + sk->err = -EINPROGRESS; + + if (sock->flags & O_NONBLOCK) { + goto out; + } + + pthread_mutex_lock(&sock->sleep.lock); + while (sock->state == SS_CONNECTING && sk->err == -EINPROGRESS) { + socket_release(sock); + wait_sleep(&sock->sleep); + socket_wr_acquire(sock); + } + pthread_mutex_unlock(&sock->sleep.lock); + socket_wr_acquire(sock); + + switch (sk->err) { + case -ETIMEDOUT: + case -ECONNREFUSED: + goto sock_error; + } + + if (sk->err != 0) { + goto out; + } + + sock->state = SS_CONNECTED; + break; + } + +out: + return sk->err; +sock_error: + rc = sk->err; + return rc; +} + +int netlink_write(struct socket *sock, const void *buf, int len) +{ + struct sock *sk = sock->sk; + + return sk->ops->write(sk, buf, len); +} + +int netlink_read(struct socket *sock, void *buf, int len) +{ + struct sock *sk = sock->sk; + + return sk->ops->read(sk, buf, len); +} + +struct sock *netlink_lookup(struct sk_buff *skb, uint16_t sport, uint16_t dport) +{ + struct socket *sock = socket_lookup(sport, dport); + if (sock == NULL) return NULL; + + return sock->sk; +} + +int netlink_close(struct socket *sock) +{ + if (!sock) { + return 0; + } + + struct sock *sk = sock->sk; + + return sock->sk->ops->close(sk); +} + +int netlink_free(struct socket *sock) +{ + struct sock *sk = sock->sk; + sock_free(sk); + free(sock->sk); + + return 0; +} + +int netlink_abort(struct socket *sock) +{ + struct sock *sk = sock->sk; + + if (sk) { + sk->ops->abort(sk); + } + + return 0; +} + +int netlink_getpeername(struct socket *sock, struct sockaddr *restrict address, + socklen_t *address_len) +{ + struct sock *sk = sock->sk; + + if (sk == NULL) { + return -1; + } + + struct sockaddr_in *res = (struct sockaddr_in *) address; + res->sin_family = AF_NETLINK; + res->sin_port = htons(sk->dport); + res->sin_addr.s_addr = htonl(sk->daddr); + *address_len = sizeof(struct sockaddr_in); + + netlink_dbg(sock, "geetpeername sin_family %d sin_port %d sin_addr %d addrlen %d", + res->sin_family, ntohs(res->sin_port), ntohl(res->sin_addr.s_addr), *address_len); + + return 0; +} +int netlink_getsockname(struct socket *sock, struct sockaddr *restrict address, + socklen_t *address_len) +{ + struct sock *sk = sock->sk; + + printf("netlink getsockname called\n"); + + if (sk == NULL) { + return -1; + } + + struct sockaddr_nl *res = (struct sockaddr_nl *) address; + res->nl_family = AF_NETLINK; + *address_len = sizeof(struct sockaddr_nl); + + return 0; +} diff --git a/src/socket.c b/src/socket.c index 0bac153..d7b6498 100644 --- a/src/socket.c +++ b/src/socket.c @@ -2,6 +2,7 @@ #include "utils.h" #include "socket.h" #include "inet.h" +#include "netlink.h" #include "wait.h" #include "timer.h" @@ -10,9 +11,11 @@ static LIST_HEAD(sockets); static pthread_rwlock_t slock = PTHREAD_RWLOCK_INITIALIZER; extern struct net_family inet; +extern struct net_family netlink; static struct net_family *families[128] = { [AF_INET] = &inet, + [AF_NETLINK] = &netlink, }; static struct socket *alloc_socket(pid_t pid) From 5bea9bf9184c0c89a1f09278c827f0d5c7b65848 Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Sat, 9 Mar 2019 18:26:14 +0200 Subject: [PATCH 06/35] Add `bind` syscall --- tools/liblevelip.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tools/liblevelip.c b/tools/liblevelip.c index 2a742ce..a757283 100644 --- a/tools/liblevelip.c +++ b/tools/liblevelip.c @@ -11,6 +11,7 @@ static int (*__start_main)(int (*main) (int, char * *, char * *), int argc, \ char * * ubp_av, void (*init) (void), void (*fini) (void), \ void (*rtld_fini) (void), void (* stack_end)); +static int (*_bind)(int socket, const struct sockaddr *address, socklen_t address_len) = NULL; static int (*_fcntl)(int fildes, int cmd, ...) = NULL; static int (*_setsockopt)(int fd, int level, int optname, const void *optval, socklen_t optlen) = NULL; @@ -786,6 +787,18 @@ int fcntl(int fildes, int cmd, ...) return rc; } +int bind(int socket, const struct sockaddr *address, socklen_t address_len) +{ + struct lvlip_sock *sock = lvlip_get_sock(socket); + + if (sock == NULL) { + /* No lvl-ip IPC socket associated */ + return _bind(socket, address, address_len); + } + + return 0; +} + int __libc_start_main(int (*main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end)) @@ -808,6 +821,7 @@ int __libc_start_main(int (*main) (int, char * *, char * *), int argc, _close = dlsym(RTLD_NEXT, "close"); _getpeername = dlsym(RTLD_NEXT, "getpeername"); _getsockname = dlsym(RTLD_NEXT, "getsockname"); + _bind = dlsym(RTLD_NEXT, "bind"); list_init(&lvlip_socks); From 8c7b80f522bda93ff925a15604d6e7f986e3e4fb Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Sat, 9 Mar 2019 18:31:04 +0200 Subject: [PATCH 07/35] Add sendmsg recvmsg placeholders --- tools/liblevelip.c | 18 ++++++++++++++++++ tools/liblevelip.h | 1 - 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/tools/liblevelip.c b/tools/liblevelip.c index a757283..59fc246 100644 --- a/tools/liblevelip.c +++ b/tools/liblevelip.c @@ -41,6 +41,8 @@ static int (*_getpeername)(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len) = NULL; static int (*_getsockname)(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len) = NULL; +static ssize_t (*_sendmsg)(int socket, const struct msghdr *message, int flags) = NULL; +static ssize_t (*_recvmsg)(int socket, struct msghdr *message, int flags) = NULL; static int lvlip_socks_count = 0; static LIST_HEAD(lvlip_socks); @@ -360,6 +362,13 @@ ssize_t sendto(int fd, const void *buf, size_t len, return write(fd, buf, len); } +ssize_t sendmsg(int socket, const struct msghdr *message, int flags) +{ + if (!lvlip_get_sock(socket)) return _sendmsg(socket, message, flags); + + return 0; +} + ssize_t recv(int fd, void *buf, size_t len, int flags) { return recvfrom(fd, buf, len, flags, NULL, 0); @@ -375,6 +384,13 @@ ssize_t recvfrom(int fd, void *restrict buf, size_t len, return read(fd, buf, len); } +ssize_t recvmsg(int socket, struct msghdr *message, int flags) +{ + if (!lvlip_get_sock(socket)) return _recvmsg(socket, message, flags); + + return 0; +} + int poll(struct pollfd *fds, nfds_t nfds, int timeout) { struct pollfd *kernel_fds[nfds]; @@ -822,6 +838,8 @@ int __libc_start_main(int (*main) (int, char * *, char * *), int argc, _getpeername = dlsym(RTLD_NEXT, "getpeername"); _getsockname = dlsym(RTLD_NEXT, "getsockname"); _bind = dlsym(RTLD_NEXT, "bind"); + _sendmsg = dlsym(RTLD_NEXT, "sendmsg"); + _recvmsg = dlsym(RTLD_NEXT, "recvmsg"); list_init(&lvlip_socks); diff --git a/tools/liblevelip.h b/tools/liblevelip.h index 07f6ffa..11519bd 100644 --- a/tools/liblevelip.h +++ b/tools/liblevelip.h @@ -3,7 +3,6 @@ #include #include -#include #include "list.h" #include "utils.h" From cb3b38788a21648e3845bfe59793c0c0e11c609c Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Mon, 11 Mar 2019 08:34:07 +0200 Subject: [PATCH 08/35] Start adding sendmsg mocked syscall --- include/ipc.h | 10 ++++++++++ include/netlink.h | 2 ++ include/socket.h | 2 ++ src/ipc.c | 20 +++++++++++++------- src/netlink.c | 29 +++++++++++++++++++++++++++++ src/socket.c | 5 +++++ tools/liblevelip.c | 34 ++++++++++++++++++++++++++++++++-- 7 files changed, 93 insertions(+), 9 deletions(-) diff --git a/include/ipc.h b/include/ipc.h index 4ae0ff9..d0094a3 100644 --- a/include/ipc.h +++ b/include/ipc.h @@ -26,6 +26,7 @@ void *start_ipc_listener(); #define IPC_SETSOCKOPT 0x0009 #define IPC_GETPEERNAME 0x000A #define IPC_GETSOCKNAME 0x000B +#define IPC_SENDMSG 0x000C struct ipc_thread { struct list_head list; @@ -105,4 +106,13 @@ struct ipc_sockname { uint8_t sa_data[128]; }; +struct ipc_sendmsg { + int sockfd; + socklen_t msg_namelen; + int msg_iovlen; + socklen_t msg_controllen; + int flags; + uint8_t buf[]; +} __attribute__((packed)); + #endif diff --git a/include/netlink.h b/include/netlink.h index 8b6e146..16db724 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -26,6 +26,8 @@ int netlink_getpeername(struct socket *sock, struct sockaddr *restrict address, socklen_t *restrict address_len); int netlink_getsockname(struct socket *sock, struct sockaddr *restrict address, socklen_t *restrict address_len); +int netlink_sendmsg(struct socket *sock, struct msghdr *message, int flags); +int netlink_recvmsg(struct socket *sock, struct msghdr *message, int flags); struct sock *netlink_lookup(struct sk_buff *skb, uint16_t sport, uint16_t dport); #endif diff --git a/include/socket.h b/include/socket.h index f9db44f..46f39ac 100644 --- a/include/socket.h +++ b/include/socket.h @@ -50,6 +50,8 @@ struct sock_ops { socklen_t *restrict address_len); int (*getsockname) (struct socket *sock, struct sockaddr *restrict addr, socklen_t *restrict address_len); + int (*sendmsg) (struct socket *sock, struct msghdr *message, int flags); + int (*recvmsg) (struct socket *sock, struct msghdr *message, int flags); }; struct net_family { diff --git a/src/ipc.c b/src/ipc.c index 714ac3e..8338eca 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -396,6 +396,17 @@ static int ipc_getsockname(int sockfd, struct ipc_msg *msg) return rc; } +static int ipc_sendmsg(int sockfd, struct ipc_msg *msg) +{ + //struct ipc_sendmsg *payload = (struct ipc_sendmsg *) msg->data; + pid_t pid = msg->pid; + int rc = -1; + + //rc = _sendmsg(pid, payload->sockfd, buf, payload->len); + + return ipc_write_rc(sockfd, pid, IPC_SENDMSG, rc); +} + static int demux_ipc_socket_call(int sockfd, char *cmdbuf, int blen) { struct ipc_msg *msg = (struct ipc_msg *)cmdbuf; @@ -403,31 +414,26 @@ static int demux_ipc_socket_call(int sockfd, char *cmdbuf, int blen) switch (msg->type) { case IPC_SOCKET: return ipc_socket(sockfd, msg); - break; case IPC_CONNECT: return ipc_connect(sockfd, msg); - break; case IPC_WRITE: return ipc_write(sockfd, msg); - break; case IPC_READ: return ipc_read(sockfd, msg); - break; case IPC_CLOSE: return ipc_close(sockfd, msg); - break; case IPC_POLL: return ipc_poll(sockfd, msg); - break; case IPC_FCNTL: return ipc_fcntl(sockfd, msg); - break; case IPC_GETSOCKOPT: return ipc_getsockopt(sockfd, msg); case IPC_GETPEERNAME: return ipc_getpeername(sockfd, msg); case IPC_GETSOCKNAME: return ipc_getsockname(sockfd, msg); + case IPC_SENDMSG: + return ipc_sendmsg(sockfd, msg); default: print_err("No such IPC type %d\n", msg->type); break; diff --git a/src/netlink.c b/src/netlink.c index d74a911..74b7d29 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -25,6 +25,8 @@ static struct sock_ops netlink_stream_ops = { .abort = &netlink_abort, .getpeername = &netlink_getpeername, .getsockname = &netlink_getsockname, + .sendmsg = &netlink_sendmsg, + .recvmsg = &netlink_recvmsg, }; static struct sock_type netlink_ops[] = { @@ -216,6 +218,7 @@ int netlink_getpeername(struct socket *sock, struct sockaddr *restrict address, return 0; } + int netlink_getsockname(struct socket *sock, struct sockaddr *restrict address, socklen_t *address_len) { @@ -233,3 +236,29 @@ int netlink_getsockname(struct socket *sock, struct sockaddr *restrict address, return 0; } + +int netlink_sendmsg(struct socket *sock, struct msghdr *message, int flags) +{ + struct sock *sk = sock->sk; + + printf("netlink sendmsg called\n"); + + if (sk == NULL) { + return -1; + } + + return 0; +} + +int netlink_recvmsg(struct socket *sock, struct msghdr *message, int flags) +{ + struct sock *sk = sock->sk; + + printf("netlink recvmsg called\n"); + + if (sk == NULL) { + return -1; + } + + return 0; +} diff --git a/src/socket.c b/src/socket.c index d7b6498..9cbb473 100644 --- a/src/socket.c +++ b/src/socket.c @@ -469,3 +469,8 @@ int _getsockname(pid_t pid, int socket, struct sockaddr *restrict address, return rc; } + +ssize_t _sendmsg(pid_t pid, int sockfd, const struct msghdr *msg, int flags) +{ + return 0; +} diff --git a/tools/liblevelip.c b/tools/liblevelip.c index 59fc246..4fa9dfe 100644 --- a/tools/liblevelip.c +++ b/tools/liblevelip.c @@ -364,9 +364,39 @@ ssize_t sendto(int fd, const void *buf, size_t len, ssize_t sendmsg(int socket, const struct msghdr *message, int flags) { - if (!lvlip_get_sock(socket)) return _sendmsg(socket, message, flags); + struct lvlip_sock *sock = lvlip_get_sock(socket); - return 0; + if (sock == NULL) return _sendmsg(socket, message, flags); + + lvl_sock_dbg("Sendmsg called", sock); + + int len = 0; + len += message->msg_namelen; + len += message->msg_iovlen; + len += message->msg_controllen; + int msglen = sizeof(struct ipc_msg) + sizeof(struct ipc_sendmsg) + len; + int pid = getpid(); + + struct ipc_msg *msg = alloca(msglen); + msg->type = IPC_SENDMSG; + msg->pid = pid; + + struct ipc_sendmsg payload = { + .msg_namelen = message->msg_namelen, + .msg_iovlen = message->msg_iovlen, + .msg_controllen = message->msg_controllen, + .flags = flags, + }; + + printf("namelen %d, iovlen %d, controllen %d\n", payload.msg_namelen, payload.msg_iovlen, payload.msg_controllen); + printf("sizeof %lu\n", sizeof(struct msghdr)); + printf("sizeof %lu\n", sizeof(struct iovec)); + + + memcpy(msg->data, &payload, sizeof(struct ipc_sendmsg)); + //memcpy(((struct ipc_sendmsg *)msg->data)->buf, buf, len); + + return transmit_lvlip(sock->lvlfd, msg, msglen); } ssize_t recv(int fd, void *buf, size_t len, int flags) From 1623c79106c92f81965a0c7d5a62786d48a663cd Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Sun, 17 Mar 2019 10:09:26 +0200 Subject: [PATCH 09/35] Start implementing Netlink & sock_diag API --- include/ipc.h | 20 ++-- include/netlink.h | 2 +- include/socket.h | 4 +- src/ipc.c | 153 ++++++++++++++++---------- src/netlink.c | 123 +++++++++++---------- src/socket.c | 15 ++- tools/Makefile | 2 +- tools/liblevelip.c | 265 ++++++++++++++++++++++++++------------------- 8 files changed, 344 insertions(+), 240 deletions(-) diff --git a/include/ipc.h b/include/ipc.h index d0094a3..8d422e9 100644 --- a/include/ipc.h +++ b/include/ipc.h @@ -7,7 +7,7 @@ #define ipc_dbg(msg, th) \ do { \ print_debug("IPC sockets count %d, current sock %d, tid %lu: %s", \ - socket_count, th->sock, th->id, msg); \ + socket_count, th->sock, th->id, msg); \ } while (0) #else #define ipc_dbg(msg, th) @@ -27,6 +27,7 @@ void *start_ipc_listener(); #define IPC_GETPEERNAME 0x000A #define IPC_GETSOCKNAME 0x000B #define IPC_SENDMSG 0x000C +#define IPC_RECVMSG 0x000D struct ipc_thread { struct list_head list; @@ -106,13 +107,18 @@ struct ipc_sockname { uint8_t sa_data[128]; }; -struct ipc_sendmsg { +struct ipc_msghdr { int sockfd; - socklen_t msg_namelen; - int msg_iovlen; - socklen_t msg_controllen; - int flags; - uint8_t buf[]; + socklen_t msg_namelen; + int msg_iovlen; + socklen_t msg_controllen; + int flags; + uint8_t data[]; +} __attribute__((packed)); + +struct ipc_iovec { + size_t iov_len; + uint8_t iov_base[]; } __attribute__((packed)); #endif diff --git a/include/netlink.h b/include/netlink.h index 16db724..01f53cc 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -26,7 +26,7 @@ int netlink_getpeername(struct socket *sock, struct sockaddr *restrict address, socklen_t *restrict address_len); int netlink_getsockname(struct socket *sock, struct sockaddr *restrict address, socklen_t *restrict address_len); -int netlink_sendmsg(struct socket *sock, struct msghdr *message, int flags); +int netlink_sendmsg(struct socket *sock, const struct msghdr *message, int flags); int netlink_recvmsg(struct socket *sock, struct msghdr *message, int flags); struct sock *netlink_lookup(struct sk_buff *skb, uint16_t sport, uint16_t dport); diff --git a/include/socket.h b/include/socket.h index 46f39ac..62a78d2 100644 --- a/include/socket.h +++ b/include/socket.h @@ -50,7 +50,7 @@ struct sock_ops { socklen_t *restrict address_len); int (*getsockname) (struct socket *sock, struct sockaddr *restrict addr, socklen_t *restrict address_len); - int (*sendmsg) (struct socket *sock, struct msghdr *message, int flags); + int (*sendmsg) (struct socket *sock, const struct msghdr *message, int flags); int (*recvmsg) (struct socket *sock, struct msghdr *message, int flags); }; @@ -85,6 +85,8 @@ int _getpeername(pid_t pid, int socket, struct sockaddr *restrict address, socklen_t *restrict address_len); int _getsockname(pid_t pid, int socket, struct sockaddr *restrict address, socklen_t *restrict address_len); +int _sendmsg (pid_t pid, int socket, const struct msghdr *message, int flags); +int _recvmsg (pid_t pid, int socket, struct msghdr *message, int flags); struct socket *socket_lookup(uint16_t sport, uint16_t dport); struct socket *socket_find(struct socket *sock); diff --git a/src/ipc.c b/src/ipc.c index 8338eca..67d7b5d 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -29,7 +29,7 @@ static void ipc_free_thread(int sock) { struct list_head *item, *tmp = NULL; struct ipc_thread *th = NULL; - + pthread_mutex_lock(&lock); list_for_each_safe(item, tmp, &sockets) { @@ -77,7 +77,7 @@ static int ipc_write_rc(int sockfd, pid_t pid, uint16_t type, int rc) err.err = 0; err.rc = rc; } - + memcpy(response->data, &err, sizeof(struct ipc_err)); if (ipc_try_send(sockfd, (char *)response, resplen) == -1) { @@ -107,7 +107,7 @@ static int ipc_read(int sockfd, struct ipc_msg *msg) print_err("Could not allocate memory for IPC read response\n"); return -1; } - + response->type = IPC_READ; response->pid = pid; @@ -133,7 +133,7 @@ static int ipc_write(int sockfd, struct ipc_msg *msg) int head = IPC_BUFLEN - sizeof(struct ipc_write) - sizeof(struct ipc_msg); char buf[payload->len]; - + memset(buf, 0, payload->len); memcpy(buf, payload->buf, payload->len > head ? head : payload->len); @@ -149,7 +149,7 @@ static int ipc_write(int sockfd, struct ipc_msg *msg) print_err("Hmm, we did not read exact payload amount in IPC write\n"); } } - + rc = _write(pid, payload->sockfd, buf, payload->len); return ipc_write_rc(sockfd, pid, IPC_WRITE, rc); @@ -226,7 +226,7 @@ static int ipc_poll(int sockfd, struct ipc_msg *msg) err.err = 0; err.rc = rc; } - + memcpy(response->data, &err, sizeof(struct ipc_err)); struct ipc_pollfd *polled = (struct ipc_pollfd *) ((struct ipc_err *)response->data)->data; @@ -240,7 +240,7 @@ static int ipc_poll(int sockfd, struct ipc_msg *msg) if (ipc_try_send(sockfd, (char *)response, resplen) == -1) { perror("Error on writing IPC poll response"); } - + return 0; } @@ -251,17 +251,17 @@ static int ipc_fcntl(int sockfd, struct ipc_msg *msg) int rc = -1; switch (fc->cmd) { - case F_GETFL: - rc = _fcntl(pid, fc->sockfd, fc->cmd); - break; - case F_SETFL: - rc = _fcntl(pid, fc->sockfd, fc->cmd, *(int *)fc->data); - break; - default: - print_err("IPC Fcntl cmd not supported %d\n", fc->cmd); - rc = -EINVAL; - } - + case F_GETFL: + rc = _fcntl(pid, fc->sockfd, fc->cmd); + break; + case F_SETFL: + rc = _fcntl(pid, fc->sockfd, fc->cmd, *(int *)fc->data); + break; + default: + print_err("IPC Fcntl cmd not supported %d\n", fc->cmd); + rc = -EINVAL; + } + return ipc_write_rc(sockfd, pid, IPC_FCNTL, rc); } @@ -294,7 +294,7 @@ static int ipc_getsockopt(int sockfd, struct ipc_msg *msg) err.err = 0; err.rc = rc; } - + memcpy(response->data, &err, sizeof(struct ipc_err)); struct ipc_sockopt *optres = (struct ipc_sockopt *) ((struct ipc_err *)response->data)->data; @@ -332,7 +332,7 @@ static int ipc_getpeername(int sockfd, struct ipc_msg *msg) struct ipc_sockname *nameres = (struct ipc_sockname *) ((struct ipc_err *)response->data)->data; rc = _getpeername(pid, name->socket, (struct sockaddr *)nameres->sa_data, &nameres->address_len); - + struct ipc_err err; if (rc < 0) { @@ -342,11 +342,11 @@ static int ipc_getpeername(int sockfd, struct ipc_msg *msg) err.err = 0; err.rc = rc; } - + memcpy(response->data, &err, sizeof(struct ipc_err)); nameres->socket = name->socket; - + if (ipc_try_send(sockfd, (char *)response, resplen) == -1) { perror("Error on writing IPC getpeername response"); } @@ -374,7 +374,7 @@ static int ipc_getsockname(int sockfd, struct ipc_msg *msg) struct ipc_sockname *nameres = (struct ipc_sockname *) ((struct ipc_err *)response->data)->data; rc = _getsockname(pid, name->socket, (struct sockaddr *)nameres->sa_data, &nameres->address_len); - + struct ipc_err err; if (rc < 0) { @@ -384,7 +384,7 @@ static int ipc_getsockname(int sockfd, struct ipc_msg *msg) err.err = 0; err.rc = rc; } - + memcpy(response->data, &err, sizeof(struct ipc_err)); nameres->socket = name->socket; @@ -396,13 +396,54 @@ static int ipc_getsockname(int sockfd, struct ipc_msg *msg) return rc; } +int init_msghdr(struct ipc_msghdr *ipc, struct msghdr *message, struct iovec *iov) +{ + uint8_t *ptr = ipc->data; + message->msg_name = ptr; + message->msg_namelen = ipc->msg_namelen; + ptr += message->msg_namelen; + + message->msg_control = ptr; + message->msg_controllen = ipc->msg_controllen; + ptr += message->msg_controllen; + + message->msg_iovlen = ipc->msg_iovlen; + + for (int i = 0; i < message->msg_iovlen; i++) { + struct ipc_iovec *v = (struct ipc_iovec *) ptr; + iov[i].iov_len = v->iov_len; + iov[i].iov_base = v->iov_base; + ptr = v->iov_base; + ptr += iov[i].iov_len; + } + + message->msg_iov = iov; + + return 0; +} + static int ipc_sendmsg(int sockfd, struct ipc_msg *msg) { - //struct ipc_sendmsg *payload = (struct ipc_sendmsg *) msg->data; + struct ipc_msghdr *payload = (struct ipc_msghdr *) msg->data; pid_t pid = msg->pid; int rc = -1; - - //rc = _sendmsg(pid, payload->sockfd, buf, payload->len); + + struct msghdr message; + struct iovec iov[payload->msg_iovlen]; + + init_msghdr(payload, &message, iov); + + for (int i = 0; i < message.msg_iovlen; i++) { + printf("iov len lol %lu\n", iov[i].iov_len); + } + + printf("Debug iovec len %d\n", (uint8_t)iov[0].iov_len); + + printf("Debg msghdr iovlen %lu, namelen %d, controllen %lu\n", message.msg_iovlen, message.msg_namelen, message.msg_controllen); + + rc = _sendmsg(pid, payload->sockfd, &message, payload->flags); + + printf("msghdr rc %d\n", rc); return ipc_write_rc(sockfd, pid, IPC_SENDMSG, rc); } @@ -412,33 +453,33 @@ static int demux_ipc_socket_call(int sockfd, char *cmdbuf, int blen) struct ipc_msg *msg = (struct ipc_msg *)cmdbuf; switch (msg->type) { - case IPC_SOCKET: - return ipc_socket(sockfd, msg); - case IPC_CONNECT: - return ipc_connect(sockfd, msg); - case IPC_WRITE: - return ipc_write(sockfd, msg); - case IPC_READ: - return ipc_read(sockfd, msg); - case IPC_CLOSE: - return ipc_close(sockfd, msg); - case IPC_POLL: - return ipc_poll(sockfd, msg); - case IPC_FCNTL: - return ipc_fcntl(sockfd, msg); - case IPC_GETSOCKOPT: - return ipc_getsockopt(sockfd, msg); - case IPC_GETPEERNAME: - return ipc_getpeername(sockfd, msg); - case IPC_GETSOCKNAME: - return ipc_getsockname(sockfd, msg); - case IPC_SENDMSG: - return ipc_sendmsg(sockfd, msg); - default: - print_err("No such IPC type %d\n", msg->type); - break; + case IPC_SOCKET: + return ipc_socket(sockfd, msg); + case IPC_CONNECT: + return ipc_connect(sockfd, msg); + case IPC_WRITE: + return ipc_write(sockfd, msg); + case IPC_READ: + return ipc_read(sockfd, msg); + case IPC_CLOSE: + return ipc_close(sockfd, msg); + case IPC_POLL: + return ipc_poll(sockfd, msg); + case IPC_FCNTL: + return ipc_fcntl(sockfd, msg); + case IPC_GETSOCKOPT: + return ipc_getsockopt(sockfd, msg); + case IPC_GETPEERNAME: + return ipc_getpeername(sockfd, msg); + case IPC_GETSOCKNAME: + return ipc_getsockname(sockfd, msg); + case IPC_SENDMSG: + return ipc_sendmsg(sockfd, msg); + default: + print_err("No such IPC type %d\n", msg->type); + break; }; - + return 0; } @@ -463,7 +504,7 @@ void *socket_ipc_open(void *args) { if (rc == -1) { perror("socket ipc read"); } - + return NULL; } @@ -474,13 +515,13 @@ void *start_ipc_listener() char *sockname = "/tmp/lvlip.socket"; unlink(sockname); - + if (strnlen(sockname, sizeof(un.sun_path)) == sizeof(un.sun_path)) { // Path is too long print_err("Path for UNIX socket is too long\n"); exit(-1); } - + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { exit_with_error(fd, "IPC listener UNIX socket"); } diff --git a/src/netlink.c b/src/netlink.c index 74b7d29..0056da8 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -8,7 +8,7 @@ extern struct net_ops tcp_ops; static int netlink_stream_connect(struct socket *sock, const struct sockaddr *addr, - int addr_len, int flags); + int addr_len, int flags); static int netlink_OPS = 1; @@ -59,9 +59,9 @@ int netlink_create(struct socket *sock, int protocol) sk = sk_alloc(skt->net_ops, protocol); sk->protocol = protocol; - + sock_init_data(sock, sk); - + return 0; } @@ -71,17 +71,17 @@ int netlink_socket(struct socket *sock, int protocol) } int netlink_connect(struct socket *sock, struct sockaddr *addr, - int addr_len, int flags) + int addr_len, int flags) { return 0; } static int netlink_stream_connect(struct socket *sock, const struct sockaddr *addr, - int addr_len, int flags) + int addr_len, int flags) { struct sock *sk = sock->sk; int rc = 0; - + if (addr_len < sizeof(addr->sa_family)) { return -EINVAL; } @@ -92,52 +92,52 @@ static int netlink_stream_connect(struct socket *sock, const struct sockaddr *ad } switch (sock->state) { - default: - sk->err = -EINVAL; - goto out; - case SS_CONNECTED: - sk->err = -EISCONN; - goto out; - case SS_CONNECTING: - sk->err = -EALREADY; - goto out; - case SS_UNCONNECTED: - sk->err = -EISCONN; - if (sk->state != TCP_CLOSE) { + default: + sk->err = -EINVAL; goto out; - } - - sk->ops->connect(sk, addr, addr_len, flags); - sock->state = SS_CONNECTING; - sk->err = -EINPROGRESS; - - if (sock->flags & O_NONBLOCK) { + case SS_CONNECTED: + sk->err = -EISCONN; goto out; - } - - pthread_mutex_lock(&sock->sleep.lock); - while (sock->state == SS_CONNECTING && sk->err == -EINPROGRESS) { - socket_release(sock); - wait_sleep(&sock->sleep); + case SS_CONNECTING: + sk->err = -EALREADY; + goto out; + case SS_UNCONNECTED: + sk->err = -EISCONN; + if (sk->state != TCP_CLOSE) { + goto out; + } + + sk->ops->connect(sk, addr, addr_len, flags); + sock->state = SS_CONNECTING; + sk->err = -EINPROGRESS; + + if (sock->flags & O_NONBLOCK) { + goto out; + } + + pthread_mutex_lock(&sock->sleep.lock); + while (sock->state == SS_CONNECTING && sk->err == -EINPROGRESS) { + socket_release(sock); + wait_sleep(&sock->sleep); + socket_wr_acquire(sock); + } + pthread_mutex_unlock(&sock->sleep.lock); socket_wr_acquire(sock); - } - pthread_mutex_unlock(&sock->sleep.lock); - socket_wr_acquire(sock); - - switch (sk->err) { - case -ETIMEDOUT: - case -ECONNREFUSED: - goto sock_error; - } - if (sk->err != 0) { - goto out; - } + switch (sk->err) { + case -ETIMEDOUT: + case -ECONNREFUSED: + goto sock_error; + } + + if (sk->err != 0) { + goto out; + } - sock->state = SS_CONNECTED; - break; + sock->state = SS_CONNECTED; + break; } - + out: return sk->err; sock_error: @@ -163,7 +163,7 @@ struct sock *netlink_lookup(struct sk_buff *skb, uint16_t sport, uint16_t dport) { struct socket *sock = socket_lookup(sport, dport); if (sock == NULL) return NULL; - + return sock->sk; } @@ -183,14 +183,14 @@ int netlink_free(struct socket *sock) struct sock *sk = sock->sk; sock_free(sk); free(sock->sk); - + return 0; } int netlink_abort(struct socket *sock) { struct sock *sk = sock->sk; - + if (sk) { sk->ops->abort(sk); } @@ -199,7 +199,7 @@ int netlink_abort(struct socket *sock) } int netlink_getpeername(struct socket *sock, struct sockaddr *restrict address, - socklen_t *address_len) + socklen_t *address_len) { struct sock *sk = sock->sk; @@ -214,13 +214,13 @@ int netlink_getpeername(struct socket *sock, struct sockaddr *restrict address, *address_len = sizeof(struct sockaddr_in); netlink_dbg(sock, "geetpeername sin_family %d sin_port %d sin_addr %d addrlen %d", - res->sin_family, ntohs(res->sin_port), ntohl(res->sin_addr.s_addr), *address_len); - + res->sin_family, ntohs(res->sin_port), ntohl(res->sin_addr.s_addr), *address_len); + return 0; } int netlink_getsockname(struct socket *sock, struct sockaddr *restrict address, - socklen_t *address_len) + socklen_t *address_len) { struct sock *sk = sock->sk; @@ -229,7 +229,7 @@ int netlink_getsockname(struct socket *sock, struct sockaddr *restrict address, if (sk == NULL) { return -1; } - + struct sockaddr_nl *res = (struct sockaddr_nl *) address; res->nl_family = AF_NETLINK; *address_len = sizeof(struct sockaddr_nl); @@ -237,7 +237,7 @@ int netlink_getsockname(struct socket *sock, struct sockaddr *restrict address, return 0; } -int netlink_sendmsg(struct socket *sock, struct msghdr *message, int flags) +int netlink_sendmsg(struct socket *sock, const struct msghdr *message, int flags) { struct sock *sk = sock->sk; @@ -246,8 +246,15 @@ int netlink_sendmsg(struct socket *sock, struct msghdr *message, int flags) if (sk == NULL) { return -1; } - - return 0; + + int rc = 0; + + printf("iovlen %lu\n", message->msg_iovlen); + for (int i = 0; imsg_iovlen; i++) { + rc += message->msg_iov[i].iov_len; + } + + return rc; } int netlink_recvmsg(struct socket *sock, struct msghdr *message, int flags) @@ -259,6 +266,6 @@ int netlink_recvmsg(struct socket *sock, struct msghdr *message, int flags) if (sk == NULL) { return -1; } - + return 0; } diff --git a/src/socket.c b/src/socket.c index 9cbb473..23ddf6d 100644 --- a/src/socket.c +++ b/src/socket.c @@ -470,7 +470,18 @@ int _getsockname(pid_t pid, int socket, struct sockaddr *restrict address, return rc; } -ssize_t _sendmsg(pid_t pid, int sockfd, const struct msghdr *msg, int flags) +int _sendmsg(pid_t pid, int socket, const struct msghdr *msg, int flags) { - return 0; + struct socket *sock; + + if ((sock = get_socket(pid, socket)) == NULL) { + print_err("Sendmsg: could not find socket (fd %u) for connection (pid %d)\n", socket, pid); + return -EBADF; + } + + socket_wr_acquire(sock); + int rc = sock->ops->sendmsg(sock, msg, flags); + socket_release(sock); + + return rc; } diff --git a/tools/Makefile b/tools/Makefile index e92019f..e317f3a 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -2,7 +2,7 @@ CPPFLAGS = -I ../include -Wall -Werror all: liblevelip -debug: CFLAGS+= -DDEBUG_API +debug: CFLAGS+= -g -DDEBUG_API debug: liblevelip liblevelip: liblevelip.c diff --git a/tools/liblevelip.c b/tools/liblevelip.c index 4fa9dfe..2bbd161 100644 --- a/tools/liblevelip.c +++ b/tools/liblevelip.c @@ -8,15 +8,15 @@ #define RCBUF_LEN 512 static int (*__start_main)(int (*main) (int, char * *, char * *), int argc, \ - char * * ubp_av, void (*init) (void), void (*fini) (void), \ - void (*rtld_fini) (void), void (* stack_end)); + char * * ubp_av, void (*init) (void), void (*fini) (void), \ + void (*rtld_fini) (void), void (* stack_end)); static int (*_bind)(int socket, const struct sockaddr *address, socklen_t address_len) = NULL; static int (*_fcntl)(int fildes, int cmd, ...) = NULL; static int (*_setsockopt)(int fd, int level, int optname, - const void *optval, socklen_t optlen) = NULL; + const void *optval, socklen_t optlen) = NULL; static int (*_getsockopt)(int fd, int level, int optname, - const void *optval, socklen_t *optlen) = NULL; + const void *optval, socklen_t *optlen) = NULL; static int (*_read)(int sockfd, void *buf, size_t len) = NULL; static int (*_write)(int sockfd, const void *buf, size_t len) = NULL; static int (*_connect)(int sockfd, const struct sockaddr *addr, socklen_t addrlen) = NULL; @@ -24,23 +24,23 @@ static int (*_socket)(int domain, int type, int protocol) = NULL; static int (*_close)(int fildes) = NULL; static int (*_poll)(struct pollfd fds[], nfds_t nfds, int timeout) = NULL; static int (*_pollchk)(struct pollfd *__fds, nfds_t __nfds, int __timeout, - __SIZE_TYPE__ __fdslen) = NULL; + __SIZE_TYPE__ __fdslen) = NULL; static int (*_ppoll)(struct pollfd *fds, nfds_t nfds, - const struct timespec *tmo_p, const sigset_t *sigmask) = NULL; + const struct timespec *tmo_p, const sigset_t *sigmask) = NULL; static int (*_select)(int nfds, fd_set *restrict readfds, - fd_set *restrict writefds, fd_set *restrict errorfds, - struct timeval *restrict timeout); + fd_set *restrict writefds, fd_set *restrict errorfds, + struct timeval *restrict timeout); static ssize_t (*_sendto)(int sockfd, const void *message, size_t length, - int flags, const struct sockaddr *dest_addr, - socklen_t dest_len) = NULL; + int flags, const struct sockaddr *dest_addr, + socklen_t dest_len) = NULL; static ssize_t (*_recvfrom)(int sockfd, void *buf, size_t len, - int flags, struct sockaddr *restrict address, - socklen_t *restrict addrlen) = NULL; + int flags, struct sockaddr *restrict address, + socklen_t *restrict addrlen) = NULL; static int (*_getpeername)(int socket, struct sockaddr *restrict address, - socklen_t *restrict address_len) = NULL; + socklen_t *restrict address_len) = NULL; static int (*_getsockname)(int socket, struct sockaddr *restrict address, - socklen_t *restrict address_len) = NULL; + socklen_t *restrict address_len) = NULL; static ssize_t (*_sendmsg)(int socket, const struct msghdr *message, int flags) = NULL; static ssize_t (*_recvmsg)(int socket, struct msghdr *message, int flags) = NULL; @@ -53,7 +53,7 @@ static inline struct lvlip_sock *lvlip_get_sock(int fd) { list_for_each(item, &lvlip_socks) { sock = list_entry(item, struct lvlip_sock, list); - + if (sock->fd == fd) return sock; }; @@ -65,15 +65,15 @@ static int is_socket_supported(int domain, int type, int protocol) int supported = 0; switch (domain) { - case AF_INET: - if (type & SOCK_STREAM && - protocol == IPPROTO_TCP) supported = 1; - break; - case AF_NETLINK: - if (protocol & NETLINK_SOCK_DIAG) supported = 1; - break; - default: - supported = 0; + case AF_INET: + if (type & SOCK_STREAM && + protocol == IPPROTO_TCP) supported = 1; + break; + case AF_NETLINK: + if (protocol & NETLINK_SOCK_DIAG) supported = 1; + break; + default: + supported = 0; } return supported; @@ -107,7 +107,7 @@ static int init_socket(char *sockname) strncpy(addr.sun_path, sockname, sizeof(addr.sun_path) - 1); ret = _connect(data_socket, (const struct sockaddr *) &addr, - sizeof(struct sockaddr_un)); + sizeof(struct sockaddr_un)); if (ret == -1) { print_err("Error connecting to level-ip. Is it up?\n"); exit(EXIT_FAILURE); @@ -134,13 +134,13 @@ static int transmit_lvlip(int lvlfd, struct ipc_msg *msg, int msglen) if (_read(lvlfd, buf, RCBUF_LEN) == -1) { perror("Could not read IPC response"); } - + struct ipc_msg *response = (struct ipc_msg *) buf; if (response->type != msg->type || response->pid != msg->pid) { print_err("ERR: IPC msg response expected type %d, pid %d\n" - " actual type %d, pid %d\n", - msg->type, msg->pid, response->type, response->pid); + " actual type %d, pid %d\n", + msg->type, msg->pid, response->type, response->pid); return -1; } @@ -158,18 +158,20 @@ int socket(int domain, int type, int protocol) } struct lvlip_sock *sock; - + int lvlfd = init_socket("/tmp/lvlip.socket"); sock = lvlip_alloc(); sock->lvlfd = lvlfd; list_add_tail(&sock->list, &lvlip_socks); lvlip_socks_count++; - + int pid = getpid(); int msglen = sizeof(struct ipc_msg) + sizeof(struct ipc_socket); struct ipc_msg *msg = alloca(msglen); + memset(msg, 0, msglen); + msg->type = IPC_SOCKET; msg->pid = pid; @@ -178,7 +180,7 @@ int socket(int domain, int type, int protocol) .type = type, .protocol = protocol }; - + memcpy(msg->data, &usersock, sizeof(struct ipc_socket)); int sockfd = transmit_lvlip(sock->lvlfd, msg, msglen); @@ -192,7 +194,7 @@ int socket(int domain, int type, int protocol) sock->fd = sockfd; lvl_sock_dbg("Socket called", sock); - + return sockfd; } @@ -206,12 +208,14 @@ int close(int fd) } lvl_sock_dbg("Close called", sock); - + int pid = getpid(); int msglen = sizeof(struct ipc_msg) + sizeof(struct ipc_close); int rc = 0; struct ipc_msg *msg = alloca(msglen); + memset(msg, 0, msglen); + msg->type = IPC_CLOSE; msg->pid = pid; @@ -234,11 +238,13 @@ int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) } lvl_sock_dbg("Connect called", sock); - + int msglen = sizeof(struct ipc_msg) + sizeof(struct ipc_connect); int pid = getpid(); - + struct ipc_msg *msg = alloca(msglen); + memset(msg, 0, msglen); + msg->type = IPC_CONNECT; msg->pid = pid; @@ -267,6 +273,8 @@ ssize_t write(int sockfd, const void *buf, size_t len) int pid = getpid(); struct ipc_msg *msg = alloca(msglen); + memset(msg, 0, msglen); + msg->type = IPC_WRITE; msg->pid = pid; @@ -296,6 +304,8 @@ ssize_t read(int sockfd, void *buf, size_t len) int msglen = sizeof(struct ipc_msg) + sizeof(struct ipc_read); struct ipc_msg *msg = alloca(msglen); + memset(msg, 0, msglen); + msg->type = IPC_READ; msg->pid = pid; @@ -319,13 +329,13 @@ ssize_t read(int sockfd, void *buf, size_t len) if (_read(sock->lvlfd, rbuf, rlen) == -1) { perror("Could not read IPC read response"); } - + struct ipc_msg *response = (struct ipc_msg *) rbuf; if (response->type != IPC_READ || response->pid != pid) { print_err("ERR: IPC read response expected: type %d, pid %d\n" - " actual: type %d, pid %d\n", - IPC_READ, pid, response->type, response->pid); + " actual: type %d, pid %d\n", + IPC_READ, pid, response->type, response->pid); return -1; } @@ -343,7 +353,7 @@ ssize_t read(int sockfd, void *buf, size_t len) memset(buf, 0, len); memcpy(buf, data->buf, data->len); - + return data->len; } @@ -353,11 +363,11 @@ ssize_t send(int fd, const void *buf, size_t len, int flags) } ssize_t sendto(int fd, const void *buf, size_t len, - int flags, const struct sockaddr *dest_addr, - socklen_t dest_len) + int flags, const struct sockaddr *dest_addr, + socklen_t dest_len) { if (!lvlip_get_sock(fd)) return _sendto(fd, buf, len, - flags, dest_addr, dest_len); + flags, dest_addr, dest_len); return write(fd, buf, len); } @@ -370,33 +380,52 @@ ssize_t sendmsg(int socket, const struct msghdr *message, int flags) lvl_sock_dbg("Sendmsg called", sock); - int len = 0; - len += message->msg_namelen; - len += message->msg_iovlen; - len += message->msg_controllen; - int msglen = sizeof(struct ipc_msg) + sizeof(struct ipc_sendmsg) + len; + int len = 0; + len += message->msg_namelen; + len += message->msg_controllen; + + for (int i = 0; i < message->msg_iovlen; i++) { + len += sizeof(size_t); + len += message->msg_iov[i].iov_len; + } + + int msglen = sizeof(struct ipc_msg) + sizeof(struct ipc_msghdr) + len; int pid = getpid(); struct ipc_msg *msg = alloca(msglen); + memset(msg, 0, msglen); + msg->type = IPC_SENDMSG; msg->pid = pid; - struct ipc_sendmsg payload = { - .msg_namelen = message->msg_namelen, - .msg_iovlen = message->msg_iovlen, - .msg_controllen = message->msg_controllen, - .flags = flags, - }; + struct ipc_msghdr *payload = (struct ipc_msghdr *)msg->data; + payload->sockfd = socket; + payload->msg_namelen = message->msg_namelen; + payload->msg_iovlen = message->msg_iovlen; + payload->msg_controllen = message->msg_controllen; + payload->flags = flags; - printf("namelen %d, iovlen %d, controllen %d\n", payload.msg_namelen, payload.msg_iovlen, payload.msg_controllen); - printf("sizeof %lu\n", sizeof(struct msghdr)); - printf("sizeof %lu\n", sizeof(struct iovec)); + uint8_t *ptr = payload->data; + memcpy(ptr, message->msg_name, payload->msg_namelen); + ptr += payload->msg_namelen; - - memcpy(msg->data, &payload, sizeof(struct ipc_sendmsg)); - //memcpy(((struct ipc_sendmsg *)msg->data)->buf, buf, len); + memcpy(ptr, message->msg_control, payload->msg_controllen); + ptr += payload->msg_controllen; - return transmit_lvlip(sock->lvlfd, msg, msglen); + for (int i = 0; i < payload->msg_iovlen; i++) { + size_t iovlen = message->msg_iov[i].iov_len; + struct ipc_iovec *v = (struct ipc_iovec *) ptr; + v->iov_len = iovlen; + printf("iovlen test %lu\n", v->iov_len); + + memcpy(v->iov_base, message->msg_iov[i].iov_base, iovlen); + ptr = v->iov_base + iovlen; + } + + int rc = transmit_lvlip(sock->lvlfd, msg, msglen); + printf("Rc %d\n", rc); + + return rc; } ssize_t recv(int fd, void *buf, size_t len, int flags) @@ -405,11 +434,11 @@ ssize_t recv(int fd, void *buf, size_t len, int flags) } ssize_t recvfrom(int fd, void *restrict buf, size_t len, - int flags, struct sockaddr *restrict address, - socklen_t *restrict addrlen) + int flags, struct sockaddr *restrict address, + socklen_t *restrict addrlen) { if (!lvlip_get_sock(fd)) return _recvfrom(fd, buf, len, - flags, address, addrlen); + flags, address, addrlen); return read(fd, buf, len); } @@ -457,7 +486,7 @@ int poll(struct pollfd *fds, nfds_t nfds, int timeout) for (int i = 0; i < kernel_nfds; i++) { lvl_dbg("Kernel nfd %d events %d timeout %d", kernel_fds[i]->fd, kernel_fds[i]->events, timeout); } - + events = _poll(*kernel_fds, kernel_nfds, timeout); if (events == -1) { @@ -470,11 +499,12 @@ int poll(struct pollfd *fds, nfds_t nfds, int timeout) if (lvlip_nfds < 1) { return events; } - + int pid = getpid(); int pollfd_size = sizeof(struct ipc_pollfd); int msglen = sizeof(struct ipc_msg) + sizeof(struct ipc_poll) + pollfd_size * lvlip_nfds; struct ipc_msg *msg = alloca(msglen); + memset(msg, 0, msglen); msg->type = IPC_POLL; msg->pid = pid; @@ -507,13 +537,13 @@ int poll(struct pollfd *fds, nfds_t nfds, int timeout) errno = EAGAIN; return -1; } - + struct ipc_msg *response = (struct ipc_msg *) rbuf; if (response->type != IPC_POLL || response->pid != pid) { print_err("ERR: IPC poll response expected: type %d, pid %d\n" - " actual: type %d, pid %d\n", - IPC_POLL, pid, response->type, response->pid); + " actual: type %d, pid %d\n", + IPC_POLL, pid, response->type, response->pid); errno = EAGAIN; return -1; } @@ -533,12 +563,12 @@ int poll(struct pollfd *fds, nfds_t nfds, int timeout) } int result = events + error->rc; - + if (result > 0 || !blocking) { for (int i = 0; i < nfds; i++) { lvl_dbg("Returning counts %d nfd %d with revents %d events %d timeout %d", result, i, fds[i].revents, fds[i].events, timeout); } - + return result; } } @@ -548,21 +578,21 @@ int poll(struct pollfd *fds, nfds_t nfds, int timeout) } int __poll_chk (struct pollfd *__fds, nfds_t __nfds, int __timeout, - __SIZE_TYPE__ __fdslen) + __SIZE_TYPE__ __fdslen) { return poll(__fds, __nfds, __timeout); } int ppoll(struct pollfd *fds, nfds_t nfds, - const struct timespec *tmo_p, const sigset_t *sigmask) + const struct timespec *tmo_p, const sigset_t *sigmask) { print_err("Ppoll called but not supported\n"); return -1; } int select(int nfds, fd_set *restrict readfds, - fd_set *restrict writefds, fd_set *restrict errorfds, - struct timeval *restrict timeout) + fd_set *restrict writefds, fd_set *restrict errorfds, + struct timeval *restrict timeout) { print_err("Select not implemented yet\n"); return _select(nfds, readfds, writefds, errorfds, timeout); @@ -570,7 +600,7 @@ int select(int nfds, fd_set *restrict readfds, int setsockopt(int fd, int level, int optname, - const void *optval, socklen_t optlen) + const void *optval, socklen_t optlen) { struct lvlip_sock *sock = lvlip_get_sock(fd); if (sock == NULL) return _setsockopt(fd, level, optname, optval, optlen); @@ -578,23 +608,25 @@ int setsockopt(int fd, int level, int optname, lvl_sock_dbg("Setsockopt called", sock); /* WARN: Setsockopt not supported yet */ - + return 0; } int getsockopt(int fd, int level, int optname, - void *optval, socklen_t *optlen) + void *optval, socklen_t *optlen) { struct lvlip_sock *sock = lvlip_get_sock(fd); if (sock == NULL) return _getsockopt(fd, level, optname, optval, optlen); lvl_sock_dbg("Getsockopt called: level %d optname %d optval %d socklen %d", - sock, level, optname, *(int *)optval, *(int *)optlen); - + sock, level, optname, *(int *)optval, *(int *)optlen); + int pid = getpid(); int msglen = sizeof(struct ipc_msg) + sizeof(struct ipc_sockopt) + *optlen; struct ipc_msg *msg = alloca(msglen); + memset(msg, 0, msglen); + msg->type = IPC_GETSOCKOPT; msg->pid = pid; @@ -621,13 +653,13 @@ int getsockopt(int fd, int level, int optname, if (_read(sock->lvlfd, rbuf, rlen) == -1) { perror("Could not read IPC getsockopt response"); } - + struct ipc_msg *response = (struct ipc_msg *) rbuf; if (response->type != IPC_GETSOCKOPT || response->pid != pid) { print_err("ERR: IPC getsockopt response expected: type %d, pid %d\n" - " actual: type %d, pid %d\n", - IPC_GETSOCKOPT, pid, response->type, response->pid); + " actual: type %d, pid %d\n", + IPC_GETSOCKOPT, pid, response->type, response->pid); return -1; } @@ -640,7 +672,7 @@ int getsockopt(int fd, int level, int optname, struct ipc_sockopt *optres = (struct ipc_sockopt *) error->data; lvl_sock_dbg("Got getsockopt level %d optname %d optval %d socklen %d", - sock, optres->level, optres->optname, *(int *)optres->optval, optres->optlen); + sock, optres->level, optres->optname, *(int *)optres->optval, optres->optlen); int val = *(int *)optres->optval; @@ -654,7 +686,7 @@ int getsockopt(int fd, int level, int optname, } int getpeername(int socket, struct sockaddr *restrict address, - socklen_t *restrict address_len) + socklen_t *restrict address_len) { struct lvlip_sock *sock = lvlip_get_sock(socket); if (sock == NULL) return _getpeername(socket, address, address_len); @@ -665,6 +697,8 @@ int getpeername(int socket, struct sockaddr *restrict address, int msglen = sizeof(struct ipc_msg) + sizeof(struct ipc_sockname); struct ipc_msg *msg = alloca(msglen); + memset(msg, 0, msglen); + msg->type = IPC_GETPEERNAME; msg->pid = pid; @@ -684,13 +718,13 @@ int getpeername(int socket, struct sockaddr *restrict address, if (_read(sock->lvlfd, rbuf, rlen) == -1) { perror("Could not read IPC getpeername response"); } - + struct ipc_msg *response = (struct ipc_msg *) rbuf; if (response->type != IPC_GETPEERNAME || response->pid != pid) { print_err("ERR: IPC getpeername response expected: type %d, pid %d\n" - " actual: type %d, pid %d\n", - IPC_GETPEERNAME, pid, response->type, response->pid); + " actual: type %d, pid %d\n", + IPC_GETPEERNAME, pid, response->type, response->pid); return -1; } @@ -703,7 +737,7 @@ int getpeername(int socket, struct sockaddr *restrict address, struct ipc_sockname *nameres = (struct ipc_sockname *) error->data; lvl_sock_dbg("Got getpeername fd %d addrlen %d sa_data %p", - sock, nameres->socket, nameres->address_len, nameres->sa_data); + sock, nameres->socket, nameres->address_len, nameres->sa_data); if (nameres->socket != socket) { print_err("Got socket %d but requested %d\n", nameres->socket, socket); @@ -711,12 +745,12 @@ int getpeername(int socket, struct sockaddr *restrict address, *address_len = nameres->address_len; memcpy(address, nameres->sa_data, nameres->address_len); - + return 0; } int getsockname(int socket, struct sockaddr *restrict address, - socklen_t *restrict address_len) + socklen_t *restrict address_len) { struct lvlip_sock *sock = lvlip_get_sock(socket); if (sock == NULL) return _getsockname(socket, address, address_len); @@ -727,6 +761,8 @@ int getsockname(int socket, struct sockaddr *restrict address, int msglen = sizeof(struct ipc_msg) + sizeof(struct ipc_sockname); struct ipc_msg *msg = alloca(msglen); + memset(msg, 0, msglen); + msg->type = IPC_GETSOCKNAME; msg->pid = pid; @@ -746,13 +782,13 @@ int getsockname(int socket, struct sockaddr *restrict address, if (_read(sock->lvlfd, rbuf, rlen) == -1) { perror("Could not read IPC getsockname response"); } - + struct ipc_msg *response = (struct ipc_msg *) rbuf; if (response->type != IPC_GETSOCKNAME || response->pid != pid) { print_err("ERR: IPC getsockname response expected: type %d, pid %d\n" - " actual: type %d, pid %d\n", - IPC_GETSOCKNAME, pid, response->type, response->pid); + " actual: type %d, pid %d\n", + IPC_GETSOCKNAME, pid, response->type, response->pid); return -1; } @@ -765,7 +801,7 @@ int getsockname(int socket, struct sockaddr *restrict address, struct ipc_sockname *nameres = (struct ipc_sockname *) error->data; lvl_sock_dbg("Got getsockname fd %d addrlen %d sa_data %p", - sock, nameres->socket, nameres->address_len, nameres->sa_data); + sock, nameres->socket, nameres->address_len, nameres->sa_data); if (nameres->socket != socket) { print_err("Got socket %d but requested %d\n", nameres->socket, socket); @@ -798,6 +834,7 @@ int fcntl(int fildes, int cmd, ...) int pid = getpid(); int msglen = sizeof(struct ipc_msg) + sizeof(struct ipc_fcntl) + sizeof(struct flock) + sizeof(int); struct ipc_msg *msg = alloca(msglen); + memset(msg, 0, msglen); msg->type = IPC_FCNTL; msg->pid = pid; @@ -805,31 +842,31 @@ int fcntl(int fildes, int cmd, ...) struct ipc_fcntl *fc = (struct ipc_fcntl *)msg->data; fc->sockfd = fildes; fc->cmd = cmd; - + switch (cmd) { - case F_GETFL: - lvl_sock_dbg("Fcntl GETFL", sock); + case F_GETFL: + lvl_sock_dbg("Fcntl GETFL", sock); - rc = transmit_lvlip(sock->lvlfd, msg, msglen); - break; - case F_SETFL: - lvl_sock_dbg("Fcntl SETFL", sock); + rc = transmit_lvlip(sock->lvlfd, msg, msglen); + break; + case F_SETFL: + lvl_sock_dbg("Fcntl SETFL", sock); - va_start(ap, cmd); + va_start(ap, cmd); - int flags = va_arg(ap, int); - memcpy(fc->data, &flags, sizeof(int)); + int flags = va_arg(ap, int); + memcpy(fc->data, &flags, sizeof(int)); - va_end(ap); + va_end(ap); - rc = transmit_lvlip(sock->lvlfd, msg, msglen); - break; - default: - rc = -1; - errno = EINVAL; - break; + rc = transmit_lvlip(sock->lvlfd, msg, msglen); + break; + default: + rc = -1; + errno = EINVAL; + break; } - + return rc; } @@ -846,8 +883,8 @@ int bind(int socket, const struct sockaddr *address, socklen_t address_len) } int __libc_start_main(int (*main) (int, char * *, char * *), int argc, - char * * ubp_av, void (*init) (void), void (*fini) (void), - void (*rtld_fini) (void), void (* stack_end)) + char * * ubp_av, void (*init) (void), void (*fini) (void), + void (*rtld_fini) (void), void (* stack_end)) { __start_main = dlsym(RTLD_NEXT, "__libc_start_main"); From e15d0b3819df48a37782b59919ea3b49becb972b Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Sun, 17 Mar 2019 11:35:53 +0200 Subject: [PATCH 10/35] Start implementing recvmsg --- src/ipc.c | 24 ++++++++++++------- src/netlink.c | 9 +------- src/socket.c | 16 +++++++++++++ tools/liblevelip.c | 57 ++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 83 insertions(+), 23 deletions(-) diff --git a/src/ipc.c b/src/ipc.c index 67d7b5d..2bcaee5 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -433,19 +433,25 @@ static int ipc_sendmsg(int sockfd, struct ipc_msg *msg) init_msghdr(payload, &message, iov); - for (int i = 0; i < message.msg_iovlen; i++) { - printf("iov len lol %lu\n", iov[i].iov_len); - } + rc = _sendmsg(pid, payload->sockfd, &message, payload->flags); - printf("Debug iovec len %d\n", (uint8_t)iov[0].iov_len); + return ipc_write_rc(sockfd, pid, IPC_SENDMSG, rc); +} + +static int ipc_recvmsg(int sockfd, struct ipc_msg *msg) +{ + struct ipc_msghdr *payload = (struct ipc_msghdr *) msg->data; + pid_t pid = msg->pid; + int rc = -1; - printf("Debg msghdr iovlen %lu, namelen %d, controllen %lu\n", message.msg_iovlen, message.msg_namelen, message.msg_controllen); + struct msghdr message; + struct iovec iov[payload->msg_iovlen]; - rc = _sendmsg(pid, payload->sockfd, &message, payload->flags); + init_msghdr(payload, &message, iov); - printf("msghdr rc %d\n", rc); + rc = _recvmsg(pid, payload->sockfd, &message, payload->flags); - return ipc_write_rc(sockfd, pid, IPC_SENDMSG, rc); + return ipc_write_rc(sockfd, pid, IPC_RECVMSG, rc); } static int demux_ipc_socket_call(int sockfd, char *cmdbuf, int blen) @@ -475,6 +481,8 @@ static int demux_ipc_socket_call(int sockfd, char *cmdbuf, int blen) return ipc_getsockname(sockfd, msg); case IPC_SENDMSG: return ipc_sendmsg(sockfd, msg); + case IPC_RECVMSG: + return ipc_recvmsg(sockfd, msg); default: print_err("No such IPC type %d\n", msg->type); break; diff --git a/src/netlink.c b/src/netlink.c index 0056da8..b4c9204 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -224,8 +224,6 @@ int netlink_getsockname(struct socket *sock, struct sockaddr *restrict address, { struct sock *sk = sock->sk; - printf("netlink getsockname called\n"); - if (sk == NULL) { return -1; } @@ -241,15 +239,12 @@ int netlink_sendmsg(struct socket *sock, const struct msghdr *message, int flags { struct sock *sk = sock->sk; - printf("netlink sendmsg called\n"); - if (sk == NULL) { return -1; } int rc = 0; - printf("iovlen %lu\n", message->msg_iovlen); for (int i = 0; imsg_iovlen; i++) { rc += message->msg_iov[i].iov_len; } @@ -261,11 +256,9 @@ int netlink_recvmsg(struct socket *sock, struct msghdr *message, int flags) { struct sock *sk = sock->sk; - printf("netlink recvmsg called\n"); - if (sk == NULL) { return -1; } - return 0; + return 1282; } diff --git a/src/socket.c b/src/socket.c index 23ddf6d..feb4ffe 100644 --- a/src/socket.c +++ b/src/socket.c @@ -485,3 +485,19 @@ int _sendmsg(pid_t pid, int socket, const struct msghdr *msg, int flags) return rc; } + +int _recvmsg(pid_t pid, int socket, struct msghdr *msg, int flags) +{ + struct socket *sock; + + if ((sock = get_socket(pid, socket)) == NULL) { + print_err("Recvmsg: could not find socket (fd %u) for connection (pid %d)\n", socket, pid); + return -EBADF; + } + + socket_rd_acquire(sock); + int rc = sock->ops->recvmsg(sock, msg, flags); + socket_release(sock); + + return rc; +} diff --git a/tools/liblevelip.c b/tools/liblevelip.c index 2bbd161..ad7cafa 100644 --- a/tools/liblevelip.c +++ b/tools/liblevelip.c @@ -416,16 +416,12 @@ ssize_t sendmsg(int socket, const struct msghdr *message, int flags) size_t iovlen = message->msg_iov[i].iov_len; struct ipc_iovec *v = (struct ipc_iovec *) ptr; v->iov_len = iovlen; - printf("iovlen test %lu\n", v->iov_len); memcpy(v->iov_base, message->msg_iov[i].iov_base, iovlen); ptr = v->iov_base + iovlen; } - int rc = transmit_lvlip(sock->lvlfd, msg, msglen); - printf("Rc %d\n", rc); - - return rc; + return transmit_lvlip(sock->lvlfd, msg, msglen); } ssize_t recv(int fd, void *buf, size_t len, int flags) @@ -445,9 +441,56 @@ ssize_t recvfrom(int fd, void *restrict buf, size_t len, ssize_t recvmsg(int socket, struct msghdr *message, int flags) { - if (!lvlip_get_sock(socket)) return _recvmsg(socket, message, flags); + struct lvlip_sock *sock = lvlip_get_sock(socket); - return 0; + if (sock == NULL) return _recvmsg(socket, message, flags); + + lvl_sock_dbg("Recvmsg called", sock); + + int len = 0; + len += message->msg_namelen; + len += message->msg_controllen; + + for (int i = 0; i < message->msg_iovlen; i++) { + len += sizeof(size_t); + len += message->msg_iov[i].iov_len; + } + + int msglen = sizeof(struct ipc_msg) + sizeof(struct ipc_msghdr) + len; + int pid = getpid(); + + struct ipc_msg *msg = alloca(msglen); + memset(msg, 0, msglen); + + msg->type = IPC_RECVMSG; + msg->pid = pid; + + struct ipc_msghdr *payload = (struct ipc_msghdr *)msg->data; + payload->sockfd = socket; + payload->msg_namelen = message->msg_namelen; + payload->msg_iovlen = message->msg_iovlen; + payload->msg_controllen = message->msg_controllen; + payload->flags = flags; + + uint8_t *ptr = payload->data; + memcpy(ptr, message->msg_name, payload->msg_namelen); + ptr += payload->msg_namelen; + + memcpy(ptr, message->msg_control, payload->msg_controllen); + ptr += payload->msg_controllen; + + for (int i = 0; i < payload->msg_iovlen; i++) { + size_t iovlen = message->msg_iov[i].iov_len; + struct ipc_iovec *v = (struct ipc_iovec *) ptr; + v->iov_len = iovlen; + + memcpy(v->iov_base, message->msg_iov[i].iov_base, iovlen); + ptr = v->iov_base + iovlen; + } + + int rc = transmit_lvlip(sock->lvlfd, msg, msglen); + + return rc; } int poll(struct pollfd *fds, nfds_t nfds, int timeout) From 45437980ffe86628abc3627a1c7440db81578f65 Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Tue, 26 Mar 2019 08:43:42 +0200 Subject: [PATCH 11/35] Mock recvmsg MSG_DONE --- include/syshead.h | 2 ++ src/ipc.c | 58 ++++++++++++++++++++++++++++++++++++++++---- src/netlink.c | 34 +++++++++++++++++++++++++- tools/liblevelip.c | 60 ++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 147 insertions(+), 7 deletions(-) diff --git a/include/syshead.h b/include/syshead.h index 3456dde..63aac83 100644 --- a/include/syshead.h +++ b/include/syshead.h @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/src/ipc.c b/src/ipc.c index 2bcaee5..72ef99c 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -396,7 +396,7 @@ static int ipc_getsockname(int sockfd, struct ipc_msg *msg) return rc; } -int init_msghdr(struct ipc_msghdr *ipc, struct msghdr *message, struct iovec *iov) +int deserialize_msghdr(struct ipc_msghdr *ipc, struct msghdr *message, struct iovec *iov) { uint8_t *ptr = ipc->data; message->msg_name = ptr; @@ -422,6 +422,28 @@ int init_msghdr(struct ipc_msghdr *ipc, struct msghdr *message, struct iovec *io return 0; } +int serialize_msghdr(struct ipc_msghdr *imh, struct msghdr *hdr) +{ + imh->msg_namelen = hdr->msg_namelen; + imh->msg_iovlen = hdr->msg_iovlen; + imh->msg_controllen = hdr->msg_controllen; + imh->flags = hdr->msg_flags; + + uint8_t *ptr = imh->data; + for (int i = 0; i < hdr->msg_iovlen; i++) { + struct ipc_iovec *v = (struct ipc_iovec *)ptr; + struct iovec *iov = &hdr->msg_iov[i]; + + v->iov_len = iov->iov_len; + memcpy(v->iov_base, iov->iov_base, iov->iov_len); + + ptr += sizeof(struct ipc_iovec); + ptr += v->iov_len; + } + + return 0; +} + static int ipc_sendmsg(int sockfd, struct ipc_msg *msg) { struct ipc_msghdr *payload = (struct ipc_msghdr *) msg->data; @@ -431,7 +453,7 @@ static int ipc_sendmsg(int sockfd, struct ipc_msg *msg) struct msghdr message; struct iovec iov[payload->msg_iovlen]; - init_msghdr(payload, &message, iov); + deserialize_msghdr(payload, &message, iov); rc = _sendmsg(pid, payload->sockfd, &message, payload->flags); @@ -447,11 +469,39 @@ static int ipc_recvmsg(int sockfd, struct ipc_msg *msg) struct msghdr message; struct iovec iov[payload->msg_iovlen]; - init_msghdr(payload, &message, iov); + deserialize_msghdr(payload, &message, iov); rc = _recvmsg(pid, payload->sockfd, &message, payload->flags); - return ipc_write_rc(sockfd, pid, IPC_RECVMSG, rc); + printf("ipc msg len is now %d\n", payload->msg_iovlen); + + int iovlen = 0; + + for (int i = 0; i < payload->msg_iovlen; i++) { + iovlen += iov[i].iov_len; + iovlen += sizeof(struct ipc_iovec); + } + + int resplen = sizeof(struct ipc_msg) + sizeof(struct ipc_err) + + sizeof(struct ipc_msghdr) + sizeof(struct ipc_iovec) + iovlen; + struct ipc_msg *response = alloca(resplen); + struct ipc_err *error = (struct ipc_err *) response->data; + struct ipc_msghdr *actual = (struct ipc_msghdr *) error->data; + + serialize_msghdr(actual, &message); + actual->sockfd = sockfd; + + response->type = IPC_RECVMSG; + response->pid = pid; + + error->rc = rc < 0 ? -1 : rc; + error->err = rc < 0 ? -rc : 0; + + if (ipc_try_send(sockfd, (char *)response, resplen) == -1) { + perror("Error on writing IPC recvmsg response"); + } + + return rc; } static int demux_ipc_socket_call(int sockfd, char *cmdbuf, int blen) diff --git a/src/netlink.c b/src/netlink.c index b4c9204..137e020 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -245,7 +245,18 @@ int netlink_sendmsg(struct socket *sock, const struct msghdr *message, int flags int rc = 0; + printf("sizeof nlmsghdr %lu\n", sizeof(struct nlmsghdr)); + for (int i = 0; imsg_iovlen; i++) { + struct iovec *v = &message->msg_iov[i]; + struct nlmsghdr *nl = v->iov_base; + struct sock_diag_req *sdr = v->iov_base + sizeof(struct nlmsghdr); + + printf("nl len %d, nl type %d, nl flags %d\n", nl->nlmsg_len, nl->nlmsg_type, nl->nlmsg_flags); + printf("sdr family %d, proto %d\n", sdr->sdiag_family, sdr->sdiag_protocol); + + printf("type is sock_diag %d\n", nl->nlmsg_type == SOCK_DIAG_BY_FAMILY); + printf("type is sock_diag %d\n", 1 == 1); rc += message->msg_iov[i].iov_len; } @@ -260,5 +271,26 @@ int netlink_recvmsg(struct socket *sock, struct msghdr *message, int flags) return -1; } - return 1282; + printf("peek %d, trunc %d\n", flags & MSG_PEEK, flags & MSG_TRUNC); + + printf("sizeof %lu\n", sizeof(struct nlmsgerr)); + + printf("recv claled\n"); + + if (flags & (MSG_PEEK | MSG_TRUNC)) { + return 20; + } + + struct iovec *v = message->msg_iov; + + struct nlmsghdr *nl = v->iov_base; + + nl->nlmsg_len = 20; + nl->nlmsg_type = NLMSG_DONE; + nl->nlmsg_flags = NLM_F_MULTI; + nl->nlmsg_seq = 123456; + nl->nlmsg_pid = 0; + v->iov_len = 20; + + return 20; } diff --git a/tools/liblevelip.c b/tools/liblevelip.c index ad7cafa..992aab8 100644 --- a/tools/liblevelip.c +++ b/tools/liblevelip.c @@ -488,9 +488,65 @@ ssize_t recvmsg(int socket, struct msghdr *message, int flags) ptr = v->iov_base + iovlen; } - int rc = transmit_lvlip(sock->lvlfd, msg, msglen); + // Send mocked syscall to lvl-ip + if (_write(sock->lvlfd, (char *)msg, msglen) == -1) { + perror("Error on writing IPC recvmsg"); + } - return rc; + int rlen = sizeof(struct ipc_msg) + sizeof(struct ipc_err) + sizeof(struct ipc_msghdr); + char rbuf[rlen]; + memset(rbuf, 0, rlen); + + // Read return value from lvl-ip + if (_read(sock->lvlfd, rbuf, rlen) == -1) { + perror("Could not read IPC recvmsg response"); + } + + struct ipc_msg *response = (struct ipc_msg *) rbuf; + + if (response->type != IPC_RECVMSG || response->pid != pid) { + print_err("ERR: IPC recvmsg response expected: type %d, pid %d\n" + " actual: type %d, pid %d\n", + IPC_RECVMSG, pid, response->type, response->pid); + return -1; + } + + struct ipc_err *error = (struct ipc_err *) response->data; + if (error->rc < 0) { + errno = error->err; + return error->rc; + } + + int iovbuf_len = sizeof(struct ipc_iovec) + error->rc; + char iovbuf[iovbuf_len]; + memset(iovbuf, 0, iovbuf_len); + + if (_read(sock->lvlfd, iovbuf, iovbuf_len) == -1) { + perror("Could not read IPC recvmsg iov response"); + } + + struct ipc_msghdr *imh = (struct ipc_msghdr *)error->data; + message->msg_iovlen = imh->msg_iovlen; + + uint8_t *iptr = (uint8_t *)iovbuf; + for (int i = 0; i < imh->msg_iovlen; i++) { + struct iovec *v = &message->msg_iov[i]; + struct ipc_iovec *iv = (struct ipc_iovec *)iptr; + + v->iov_len = iv->iov_len; + memcpy(v->iov_base, iv->iov_base, iv->iov_len); + + iptr += sizeof(struct ipc_iovec); + iptr += iv->iov_len; + } + + if (message->msg_iov[0].iov_len > 0) { + struct nlmsghdr *nl = message->msg_iov[0].iov_base; + + printf("%d\n", nl->nlmsg_type); + } + + return error->rc; } int poll(struct pollfd *fds, nfds_t nfds, int timeout) From fa0a6511707b9650bcbdb6982251c5fcbc9bfd90 Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Fri, 29 Mar 2019 08:45:08 +0200 Subject: [PATCH 12/35] Support MSG_PEEK in recvmsg --- src/ipc.c | 2 +- src/netlink.c | 11 +++-------- tools/liblevelip.c | 13 +++++++++++-- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/ipc.c b/src/ipc.c index 72ef99c..2b97174 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -483,7 +483,7 @@ static int ipc_recvmsg(int sockfd, struct ipc_msg *msg) } int resplen = sizeof(struct ipc_msg) + sizeof(struct ipc_err) + - sizeof(struct ipc_msghdr) + sizeof(struct ipc_iovec) + iovlen; + sizeof(struct ipc_msghdr) + iovlen; struct ipc_msg *response = alloca(resplen); struct ipc_err *error = (struct ipc_err *) response->data; struct ipc_msghdr *actual = (struct ipc_msghdr *) error->data; diff --git a/src/netlink.c b/src/netlink.c index 137e020..cb623e5 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -271,20 +271,15 @@ int netlink_recvmsg(struct socket *sock, struct msghdr *message, int flags) return -1; } - printf("peek %d, trunc %d\n", flags & MSG_PEEK, flags & MSG_TRUNC); - - printf("sizeof %lu\n", sizeof(struct nlmsgerr)); + struct iovec *v = message->msg_iov; - printf("recv claled\n"); + struct nlmsghdr *nl = v->iov_base; if (flags & (MSG_PEEK | MSG_TRUNC)) { + nl->nlmsg_flags = MSG_TRUNC; return 20; } - struct iovec *v = message->msg_iov; - - struct nlmsghdr *nl = v->iov_base; - nl->nlmsg_len = 20; nl->nlmsg_type = NLMSG_DONE; nl->nlmsg_flags = NLM_F_MULTI; diff --git a/tools/liblevelip.c b/tools/liblevelip.c index 992aab8..dd02049 100644 --- a/tools/liblevelip.c +++ b/tools/liblevelip.c @@ -502,6 +502,8 @@ ssize_t recvmsg(int socket, struct msghdr *message, int flags) perror("Could not read IPC recvmsg response"); } + lvl_sock_dbg("Recvmsg reading %d bytes for header", sock, rlen); + struct ipc_msg *response = (struct ipc_msg *) rbuf; if (response->type != IPC_RECVMSG || response->pid != pid) { @@ -517,16 +519,23 @@ ssize_t recvmsg(int socket, struct msghdr *message, int flags) return error->rc; } + struct ipc_msghdr *imh = (struct ipc_msghdr *)error->data; + message->msg_iovlen = imh->msg_iovlen; + int iovbuf_len = sizeof(struct ipc_iovec) + error->rc; char iovbuf[iovbuf_len]; memset(iovbuf, 0, iovbuf_len); + lvl_sock_dbg("Recvmsg reading %d bytes for iov", sock, iovbuf_len); + if (_read(sock->lvlfd, iovbuf, iovbuf_len) == -1) { perror("Could not read IPC recvmsg iov response"); } - struct ipc_msghdr *imh = (struct ipc_msghdr *)error->data; - message->msg_iovlen = imh->msg_iovlen; + if (flags & MSG_TRUNC || flags & MSG_PEEK) { + lvl_sock_dbg("Recvmsg returning %d bytes because of trunc or peek", sock, error->rc); + return error->rc; + } uint8_t *iptr = (uint8_t *)iovbuf; for (int i = 0; i < imh->msg_iovlen; i++) { From ad680cc0d0e9bcf992586314e78a0479bf3dac89 Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Fri, 29 Mar 2019 09:46:06 +0200 Subject: [PATCH 13/35] Improve recvmsg debug prints --- src/netlink.c | 1 + tools/liblevelip.c | 26 +++++++++++++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/netlink.c b/src/netlink.c index cb623e5..0ac21b3 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -274,6 +274,7 @@ int netlink_recvmsg(struct socket *sock, struct msghdr *message, int flags) struct iovec *v = message->msg_iov; struct nlmsghdr *nl = v->iov_base; + memset(nl, 0, sizeof(struct nlmsghdr)); if (flags & (MSG_PEEK | MSG_TRUNC)) { nl->nlmsg_flags = MSG_TRUNC; diff --git a/tools/liblevelip.c b/tools/liblevelip.c index dd02049..9fa17db 100644 --- a/tools/liblevelip.c +++ b/tools/liblevelip.c @@ -421,7 +421,11 @@ ssize_t sendmsg(int socket, const struct msghdr *message, int flags) ptr = v->iov_base + iovlen; } - return transmit_lvlip(sock->lvlfd, msg, msglen); + int rc = transmit_lvlip(sock->lvlfd, msg, msglen); + + lvl_sock_dbg("Sendmsg returning rc %d", sock, rc); + + return rc; } ssize_t recv(int fd, void *buf, size_t len, int flags) @@ -445,7 +449,8 @@ ssize_t recvmsg(int socket, struct msghdr *message, int flags) if (sock == NULL) return _recvmsg(socket, message, flags); - lvl_sock_dbg("Recvmsg called", sock); + lvl_sock_dbg("Recvmsg called with flags MSG_PEEK %d, MSG_TRUNC %d", sock, + flags & MSG_PEEK, flags & MSG_TRUNC); int len = 0; len += message->msg_namelen; @@ -549,11 +554,18 @@ ssize_t recvmsg(int socket, struct msghdr *message, int flags) iptr += iv->iov_len; } - if (message->msg_iov[0].iov_len > 0) { - struct nlmsghdr *nl = message->msg_iov[0].iov_base; - - printf("%d\n", nl->nlmsg_type); - } + struct nlmsghdr *nl = message->msg_iov[0].iov_base; + + lvl_sock_dbg("Recvmsg nlmsghdr len %d, seq %d, pid %d, " \ + "NLMSG_ERROR %d, NLMSG_DONE %d, NL_F_MULTI %d", + sock, + nl->nlmsg_len, + nl->nlmsg_seq, + nl->nlmsg_pid, + nl->nlmsg_type == NLMSG_ERROR, + nl->nlmsg_type == NLMSG_DONE, + nl->nlmsg_flags == NLM_F_MULTI); + lvl_sock_dbg("Recvmsg returning rc %d", sock, error->rc); return error->rc; } From 6779d9034f1870ae81d9ab5c82a8ff755037691b Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Sun, 31 Mar 2019 12:54:14 +0300 Subject: [PATCH 14/35] Set Netlink pid to 0 for kernel-like communication This is enforced by e.g. the `ss` tool. --- src/netlink.c | 8 ++++++-- tools/liblevelip.c | 20 +++++++++----------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/netlink.c b/src/netlink.c index 0ac21b3..3d52aab 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -230,6 +230,7 @@ int netlink_getsockname(struct socket *sock, struct sockaddr *restrict address, struct sockaddr_nl *res = (struct sockaddr_nl *) address; res->nl_family = AF_NETLINK; + res->nl_pid = 0; *address_len = sizeof(struct sockaddr_nl); return 0; @@ -245,14 +246,13 @@ int netlink_sendmsg(struct socket *sock, const struct msghdr *message, int flags int rc = 0; - printf("sizeof nlmsghdr %lu\n", sizeof(struct nlmsghdr)); - for (int i = 0; imsg_iovlen; i++) { struct iovec *v = &message->msg_iov[i]; struct nlmsghdr *nl = v->iov_base; struct sock_diag_req *sdr = v->iov_base + sizeof(struct nlmsghdr); printf("nl len %d, nl type %d, nl flags %d\n", nl->nlmsg_len, nl->nlmsg_type, nl->nlmsg_flags); + printf("nl pid %d, nl seq %d\n", nl->nlmsg_pid, nl->nlmsg_seq); printf("sdr family %d, proto %d\n", sdr->sdiag_family, sdr->sdiag_protocol); printf("type is sock_diag %d\n", nl->nlmsg_type == SOCK_DIAG_BY_FAMILY); @@ -271,6 +271,8 @@ int netlink_recvmsg(struct socket *sock, struct msghdr *message, int flags) return -1; } + struct sockaddr_nl *snl = message->msg_name; + memset(snl, 0, sizeof(struct sockaddr_nl)); struct iovec *v = message->msg_iov; struct nlmsghdr *nl = v->iov_base; @@ -288,5 +290,7 @@ int netlink_recvmsg(struct socket *sock, struct msghdr *message, int flags) nl->nlmsg_pid = 0; v->iov_len = 20; + printf("Returning nlmsghdr: nlmsg_type DONE %d, flags MULTI %d\n", nl->nlmsg_type & NLMSG_DONE, nl->nlmsg_flags & NLM_F_MULTI); + return 20; } diff --git a/tools/liblevelip.c b/tools/liblevelip.c index 9fa17db..3f9b86c 100644 --- a/tools/liblevelip.c +++ b/tools/liblevelip.c @@ -423,6 +423,9 @@ ssize_t sendmsg(int socket, const struct msghdr *message, int flags) int rc = transmit_lvlip(sock->lvlfd, msg, msglen); + struct sockaddr_nl *snl = message->msg_name; + snl->nl_pid = 0; + lvl_sock_dbg("Sendmsg returning rc %d", sock, rc); return rc; @@ -554,17 +557,12 @@ ssize_t recvmsg(int socket, struct msghdr *message, int flags) iptr += iv->iov_len; } - struct nlmsghdr *nl = message->msg_iov[0].iov_base; - - lvl_sock_dbg("Recvmsg nlmsghdr len %d, seq %d, pid %d, " \ - "NLMSG_ERROR %d, NLMSG_DONE %d, NL_F_MULTI %d", - sock, - nl->nlmsg_len, - nl->nlmsg_seq, - nl->nlmsg_pid, - nl->nlmsg_type == NLMSG_ERROR, - nl->nlmsg_type == NLMSG_DONE, - nl->nlmsg_flags == NLM_F_MULTI); + struct sockaddr_nl *snl = message->msg_name; + snl->nl_family = AF_NETLINK; + snl->nl_pad = 0; + snl->nl_pid = 0; + snl->nl_groups = 0; + lvl_sock_dbg("Recvmsg returning rc %d", sock, error->rc); return error->rc; From 06da9ff0d77766c7d7ba1c7c8a101e4a17a4efd2 Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Sun, 31 Mar 2019 12:54:41 +0300 Subject: [PATCH 15/35] Do not take a pointer to packed struct member This is an error with clang, so avoid it. --- src/ipc.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/ipc.c b/src/ipc.c index 2b97174..17355b7 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -161,7 +161,12 @@ static int ipc_connect(int sockfd, struct ipc_msg *msg) pid_t pid = msg->pid; int rc = -1; - rc = _connect(pid, payload->sockfd, &payload->addr, payload->addrlen); + struct sockaddr addr; + + addr.sa_family = payload->addr.sa_family; + memcpy(addr.sa_data, payload->addr.sa_data, sizeof(addr.sa_data)); + + rc = _connect(pid, payload->sockfd, &addr, payload->addrlen); return ipc_write_rc(sockfd, pid, IPC_CONNECT, rc); } @@ -272,9 +277,11 @@ static int ipc_getsockopt(int sockfd, struct ipc_msg *msg) pid_t pid = msg->pid; int rc = -1; - rc = _getsockopt(pid, opts->fd, opts->level, opts->optname, opts->optval, &opts->optlen); + socklen_t optlen; - int resplen = sizeof(struct ipc_msg) + sizeof(struct ipc_err) + sizeof(struct ipc_sockopt) + opts->optlen; + rc = _getsockopt(pid, opts->fd, opts->level, opts->optname, opts->optval, &optlen); + + int resplen = sizeof(struct ipc_msg) + sizeof(struct ipc_err) + sizeof(struct ipc_sockopt) + optlen; struct ipc_msg *response = alloca(resplen); if (response == NULL) { @@ -302,8 +309,8 @@ static int ipc_getsockopt(int sockfd, struct ipc_msg *msg) optres->fd = opts->fd; optres->level = opts->level; optres->optname = opts->optname; - optres->optlen = opts->optlen; - memcpy(&optres->optval, opts->optval, opts->optlen); + optres->optlen = optlen; + memcpy(&optres->optval, opts->optval, optlen); if (ipc_try_send(sockfd, (char *)response, resplen) == -1) { perror("Error on writing IPC getsockopt response"); @@ -497,6 +504,8 @@ static int ipc_recvmsg(int sockfd, struct ipc_msg *msg) error->rc = rc < 0 ? -1 : rc; error->err = rc < 0 ? -rc : 0; + printf("IPC recvmsg sending %d bytes\n", resplen); + if (ipc_try_send(sockfd, (char *)response, resplen) == -1) { perror("Error on writing IPC recvmsg response"); } From 589076ea6fc9a9e1db2912ba69bd72ae21249160 Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Sun, 31 Mar 2019 12:56:30 +0300 Subject: [PATCH 16/35] Add Troubleshooting to getting-started document --- Documentation/getting-started.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Documentation/getting-started.md b/Documentation/getting-started.md index 929e014..f388b60 100644 --- a/Documentation/getting-started.md +++ b/Documentation/getting-started.md @@ -87,3 +87,28 @@ Try browsing the Web, with Level-IP doing the packet transfer: [saminiir@localhost tools]$ ./level-ip firefox google.com That's it! + + +# Troubleshooting + +Common errors: + +## Tun module not loaded/available + +`tun` is required to be loaded: + +``` +$ lsmod | grep tun +tun 57344 2 +``` + +Try loading it +``` +$ modprobe tun +``` + +Otherwise, consult your distro's documentation on setting it up. + +## Missing capabilities for Level-IP + +`lvl-ip` requires the `CAP_NET_ADMIN` capability to bind to the tap device. From e3c728283513eec3dc781fafc1e38381b18635a6 Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Mon, 1 Apr 2019 07:58:02 +0300 Subject: [PATCH 17/35] Add "dummy" protocol for TCP --- tools/liblevelip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/liblevelip.c b/tools/liblevelip.c index 3f9b86c..0e8877c 100644 --- a/tools/liblevelip.c +++ b/tools/liblevelip.c @@ -67,7 +67,7 @@ static int is_socket_supported(int domain, int type, int protocol) switch (domain) { case AF_INET: if (type & SOCK_STREAM && - protocol == IPPROTO_TCP) supported = 1; + (protocol == IPPROTO_TCP || protocol == 0)) supported = 1; break; case AF_NETLINK: if (protocol & NETLINK_SOCK_DIAG) supported = 1; From 95984d49451a9c905336c9b84d457b1f11cfad4e Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Wed, 3 Apr 2019 08:32:23 +0300 Subject: [PATCH 18/35] Store Netlink messages to a list --- include/netlink.h | 7 +++++++ src/netlink.c | 27 ++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/include/netlink.h b/include/netlink.h index 01f53cc..b4024a4 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -14,6 +14,13 @@ #define netlink_dbg(msg, th, ...) #endif +struct nl_message { + struct list_head list; + struct socket *sock; + struct nlmsghdr nl; + uint8_t data[]; +}; + int netlink_create(struct socket *sock, int protocol); int netlink_socket(struct socket *sock, int protocol); int netlink_connect(struct socket *sock, struct sockaddr *addr, int addr_len, int flags); diff --git a/src/netlink.c b/src/netlink.c index 3d52aab..16c448b 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -7,11 +7,16 @@ extern struct net_ops tcp_ops; +static int message_amount = 0; +static LIST_HEAD(messages); +static pthread_rwlock_t mlock = PTHREAD_RWLOCK_INITIALIZER; + static int netlink_stream_connect(struct socket *sock, const struct sockaddr *addr, int addr_len, int flags); static int netlink_OPS = 1; + struct net_family netlink = { .create = netlink_create, }; @@ -38,6 +43,18 @@ static struct sock_type netlink_ops[] = { } }; +struct nl_message *alloc_message(struct socket *sock, const struct nlmsghdr *nl, void *payload, int flags) +{ + struct nl_message *nlmsg = malloc(sizeof (struct nl_message) + nl->nlmsg_len); + list_init(&nlmsg->list); + + nlmsg->sock = sock; + memcpy(&nlmsg->nl, nl, sizeof(struct nlmsghdr)); + memcpy(nlmsg->data, payload, nl->nlmsg_len); + + return nlmsg; +} + int netlink_create(struct socket *sock, int protocol) { struct sock *sk; @@ -245,19 +262,27 @@ int netlink_sendmsg(struct socket *sock, const struct msghdr *message, int flags } int rc = 0; + struct nl_message *nlmsg; for (int i = 0; imsg_iovlen; i++) { struct iovec *v = &message->msg_iov[i]; struct nlmsghdr *nl = v->iov_base; struct sock_diag_req *sdr = v->iov_base + sizeof(struct nlmsghdr); + nlmsg = alloc_message(sock, nl, (void *)sdr, 0); + + pthread_rwlock_wrlock(&mlock); + list_add_tail(&nlmsg->list, &messages); + message_amount++; + pthread_rwlock_unlock(&mlock); + printf("nl len %d, nl type %d, nl flags %d\n", nl->nlmsg_len, nl->nlmsg_type, nl->nlmsg_flags); printf("nl pid %d, nl seq %d\n", nl->nlmsg_pid, nl->nlmsg_seq); printf("sdr family %d, proto %d\n", sdr->sdiag_family, sdr->sdiag_protocol); printf("type is sock_diag %d\n", nl->nlmsg_type == SOCK_DIAG_BY_FAMILY); printf("type is sock_diag %d\n", 1 == 1); - rc += message->msg_iov[i].iov_len; + rc += nl->nlmsg_len; } return rc; From 69c6a6a84c261553cf6e70073d735a1bceb69b1b Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Thu, 4 Apr 2019 08:51:31 +0300 Subject: [PATCH 19/35] Find socket's netlink request from list --- include/netlink.h | 2 +- src/netlink.c | 34 +++++++++++++++++++++++++++++++--- src/socket.c | 2 +- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/include/netlink.h b/include/netlink.h index b4024a4..b9fc8bb 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -16,7 +16,7 @@ struct nl_message { struct list_head list; - struct socket *sock; + int fd; struct nlmsghdr nl; uint8_t data[]; }; diff --git a/src/netlink.c b/src/netlink.c index 16c448b..81522f6 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -45,12 +45,13 @@ static struct sock_type netlink_ops[] = { struct nl_message *alloc_message(struct socket *sock, const struct nlmsghdr *nl, void *payload, int flags) { - struct nl_message *nlmsg = malloc(sizeof (struct nl_message) + nl->nlmsg_len); + int payload_size = nl->nlmsg_len - sizeof(struct nlmsghdr); + struct nl_message *nlmsg = malloc(sizeof (struct nl_message) + payload_size); list_init(&nlmsg->list); - nlmsg->sock = sock; + nlmsg->fd = sock->fd; memcpy(&nlmsg->nl, nl, sizeof(struct nlmsghdr)); - memcpy(nlmsg->data, payload, nl->nlmsg_len); + memcpy(nlmsg->data, payload, payload_size); return nlmsg; } @@ -264,6 +265,8 @@ int netlink_sendmsg(struct socket *sock, const struct msghdr *message, int flags int rc = 0; struct nl_message *nlmsg; + printf("Netlink message amount %d\n", message_amount); + for (int i = 0; imsg_iovlen; i++) { struct iovec *v = &message->msg_iov[i]; struct nlmsghdr *nl = v->iov_base; @@ -288,6 +291,25 @@ int netlink_sendmsg(struct socket *sock, const struct msghdr *message, int flags return rc; } +struct nl_message *find_netlink_request(int sockfd) +{ + struct list_head *item; + struct nl_message *entry; + struct nl_message *nlm = NULL; + + pthread_rwlock_wrlock(&mlock); + list_for_each(item, &messages) { + entry = list_entry(item, struct nl_message, list); + + if (entry->fd == sockfd) { + nlm = entry; + } + } + pthread_rwlock_unlock(&mlock); + + return nlm; +} + int netlink_recvmsg(struct socket *sock, struct msghdr *message, int flags) { struct sock *sk = sock->sk; @@ -303,6 +325,12 @@ int netlink_recvmsg(struct socket *sock, struct msghdr *message, int flags) struct nlmsghdr *nl = v->iov_base; memset(nl, 0, sizeof(struct nlmsghdr)); + struct nl_message *nlm = find_netlink_request(sock->fd); + + if (nlm == NULL) { + return -EBADF; + } + if (flags & (MSG_PEEK | MSG_TRUNC)) { nl->nlmsg_flags = MSG_TRUNC; return 20; diff --git a/src/socket.c b/src/socket.c index feb4ffe..b0bcec9 100644 --- a/src/socket.c +++ b/src/socket.c @@ -44,7 +44,7 @@ static struct socket *alloc_socket(pid_t pid) int socket_rd_acquire(struct socket *sock) { - int rc = pthread_rwlock_wrlock(&sock->lock); + int rc = pthread_rwlock_rdlock(&sock->lock); sock->refcnt++; return rc; } From ec0bcd389d6d8dcc307568fff0df1e3bca9bc7f7 Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Thu, 4 Apr 2019 08:54:33 +0300 Subject: [PATCH 20/35] Add stub function for demuxing netlink request --- include/netlink.h | 2 +- src/netlink.c | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/include/netlink.h b/include/netlink.h index b9fc8bb..b4024a4 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -16,7 +16,7 @@ struct nl_message { struct list_head list; - int fd; + struct socket *sock; struct nlmsghdr nl; uint8_t data[]; }; diff --git a/src/netlink.c b/src/netlink.c index 81522f6..558d2cc 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -49,7 +49,7 @@ struct nl_message *alloc_message(struct socket *sock, const struct nlmsghdr *nl, struct nl_message *nlmsg = malloc(sizeof (struct nl_message) + payload_size); list_init(&nlmsg->list); - nlmsg->fd = sock->fd; + nlmsg->sock = sock; memcpy(&nlmsg->nl, nl, sizeof(struct nlmsghdr)); memcpy(nlmsg->data, payload, payload_size); @@ -301,7 +301,7 @@ struct nl_message *find_netlink_request(int sockfd) list_for_each(item, &messages) { entry = list_entry(item, struct nl_message, list); - if (entry->fd == sockfd) { + if (entry->sock->fd == sockfd) { nlm = entry; } } @@ -310,6 +310,11 @@ struct nl_message *find_netlink_request(int sockfd) return nlm; } +int demux_netlink_request(struct nlmsghdr *nl, struct nl_message *nlm) +{ + return 20; +} + int netlink_recvmsg(struct socket *sock, struct msghdr *message, int flags) { struct sock *sk = sock->sk; @@ -327,13 +332,15 @@ int netlink_recvmsg(struct socket *sock, struct msghdr *message, int flags) struct nl_message *nlm = find_netlink_request(sock->fd); + int rc = demux_netlink_request(nl, nlm); + if (nlm == NULL) { return -EBADF; } if (flags & (MSG_PEEK | MSG_TRUNC)) { nl->nlmsg_flags = MSG_TRUNC; - return 20; + return rc; } nl->nlmsg_len = 20; From 59fc461eb44f79a6485020e0db0db165bef9fb82 Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Fri, 5 Apr 2019 08:51:30 +0300 Subject: [PATCH 21/35] Start demuxing Netlink request into response --- src/netlink.c | 65 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/src/netlink.c b/src/netlink.c index 558d2cc..ae23c43 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -310,11 +310,56 @@ struct nl_message *find_netlink_request(int sockfd) return nlm; } -int demux_netlink_request(struct nlmsghdr *nl, struct nl_message *nlm) +int process_netlink_request_tcp(struct nlmsghdr *nl, struct nl_message *req) { return 20; } +int process_netlink_request_not_supported(struct nlmsghdr *nl, struct nl_message *req) +{ + return 20; +} + +int demux_netlink_request(struct nlmsghdr *nl, struct nl_message *req, int flags) +{ + int rc = -1; + + struct sock_diag_req *sdr = (struct sock_diag_req *)req->data; + + switch (sdr->sdiag_family) { + case AF_INET: + switch (sdr->sdiag_protocol) { + case IPPROTO_TCP: + rc = process_netlink_request_tcp(nl, req); + break; + default: + rc = process_netlink_request_not_supported(nl, req); + break; + } + break; + default: + rc = process_netlink_request_not_supported(nl, req); + break; + } + + if (flags & (MSG_PEEK | MSG_TRUNC)) { + // Empty out msg_iov contents + nl->nlmsg_flags = MSG_TRUNC; + return rc; + } + + // Remove nl_message from list + nl->nlmsg_len = 20; + nl->nlmsg_type = NLMSG_DONE; + nl->nlmsg_flags = NLM_F_MULTI; + nl->nlmsg_seq = 123456; + nl->nlmsg_pid = 0; + + printf("Returning nlmsghdr: nlmsg_type DONE %d, flags MULTI %d\n", nl->nlmsg_type & NLMSG_DONE, nl->nlmsg_flags & NLM_F_MULTI); + + return rc; +} + int netlink_recvmsg(struct socket *sock, struct msghdr *message, int flags) { struct sock *sk = sock->sk; @@ -332,25 +377,13 @@ int netlink_recvmsg(struct socket *sock, struct msghdr *message, int flags) struct nl_message *nlm = find_netlink_request(sock->fd); - int rc = demux_netlink_request(nl, nlm); - if (nlm == NULL) { return -EBADF; } - if (flags & (MSG_PEEK | MSG_TRUNC)) { - nl->nlmsg_flags = MSG_TRUNC; - return rc; - } - - nl->nlmsg_len = 20; - nl->nlmsg_type = NLMSG_DONE; - nl->nlmsg_flags = NLM_F_MULTI; - nl->nlmsg_seq = 123456; - nl->nlmsg_pid = 0; - v->iov_len = 20; + int rc = demux_netlink_request(nl, nlm, flags); - printf("Returning nlmsghdr: nlmsg_type DONE %d, flags MULTI %d\n", nl->nlmsg_type & NLMSG_DONE, nl->nlmsg_flags & NLM_F_MULTI); + v->iov_len = rc; - return 20; + return rc; } From 52c239b160ac1c919dd2efe434747025e5b5b722 Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Tue, 9 Apr 2019 08:42:10 +0300 Subject: [PATCH 22/35] Implement basic Netlink socket filtering callback --- include/socket.h | 3 +++ src/netlink.c | 39 ++++++++++++++++++++++++++++++++++- src/socket.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++-- src/tuntap_if.c | 2 +- 4 files changed, 93 insertions(+), 4 deletions(-) diff --git a/include/socket.h b/include/socket.h index 62a78d2..5b1f7fa 100644 --- a/include/socket.h +++ b/include/socket.h @@ -64,6 +64,7 @@ struct socket { pid_t pid; int refcnt; enum socket_state state; + int family; short type; int flags; struct sock *sk; @@ -90,6 +91,8 @@ int _recvmsg (pid_t pid, int socket, struct msghdr *message, int flags); struct socket *socket_lookup(uint16_t sport, uint16_t dport); struct socket *socket_find(struct socket *sock); +int filter_sockets(int family, int proto, uint8_t **store, + int (*f)(struct socket *s, uint8_t *ptr), int size); int socket_rd_acquire(struct socket *sock); int socket_wr_acquire(struct socket *sock); int socket_release(struct socket *sock); diff --git a/src/netlink.c b/src/netlink.c index ae23c43..d5bd888 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -310,9 +310,46 @@ struct nl_message *find_netlink_request(int sockfd) return nlm; } +int convert_socket_to_inet_tcp_diag_msg(struct socket *s, uint8_t *ptr) +{ + struct inet_diag_msg *idm = (struct inet_diag_msg *) ptr; + + idm->idiag_family = AF_INET; + idm->idiag_state = TCP_ESTABLISHED; + idm->idiag_timer = 0; + idm->idiag_retrans = 0; + idm->idiag_expires = 0; + idm->idiag_rqueue = 0; + idm->idiag_wqueue = 0; + idm->idiag_uid = 0; + idm->idiag_inode = 0; + + return sizeof(struct inet_diag_msg); +} + int process_netlink_request_tcp(struct nlmsghdr *nl, struct nl_message *req) { - return 20; + + struct inet_diag_msg *idm = (struct inet_diag_msg *)(nl + sizeof(struct nlmsghdr)); + //struct sock_diag_req *sdr = (struct sock_diag_req *)(req->data); + idm->idiag_family = AF_INET; + + struct inet_diag_msg *tmp = NULL; + + int rc = filter_sockets(AF_INET, IPPROTO_TCP, (uint8_t **)&tmp, convert_socket_to_inet_tcp_diag_msg, sizeof(struct inet_diag_msg)); + + if (rc < 0) { + perror("Failed on netlink TCP processing"); + return -1; + } + + printf("Pointer memory location %p\n", tmp); + + for (int i = 0; i < rc; i++) { + printf("received inet_diag_msg %d\n", tmp[i].idiag_family); + } + + return rc; } int process_netlink_request_not_supported(struct nlmsghdr *nl, struct nl_message *req) diff --git a/src/socket.c b/src/socket.c index b0bcec9..e8a9ced 100644 --- a/src/socket.c +++ b/src/socket.c @@ -44,7 +44,7 @@ static struct socket *alloc_socket(pid_t pid) int socket_rd_acquire(struct socket *sock) { - int rc = pthread_rwlock_rdlock(&sock->lock); + int rc = pthread_rwlock_wrlock(&sock->lock); sock->refcnt++; return rc; } @@ -184,6 +184,52 @@ struct socket *socket_find(struct socket *find) return sock; } +int filter_sockets(int family, int proto, uint8_t **store, + int (*f)(struct socket *s, uint8_t *ptr), int size) +{ + struct list_head *item; + struct socket *sock = NULL; + + int rc = 0; + int allocated = 0; + int amount = 0; + + // Socket mutex should already be locked upstairs + + list_for_each(item, &sockets) { + sock = list_entry(item, struct socket, list); + + if (sock->family == family && sock->sk->protocol == proto) { + allocated += size; + + *store = realloc(*store, allocated); + if (*store == NULL) { + perror("Failed on allocating socket filter store memory"); + goto error; + } + + rc = f(sock, *store); + + if (rc < 0) { + perror("Failed on socket filtering"); + goto error; + } + + amount++; + store += rc; + } + } + + printf("Iterated through sockets %d\n", amount); + + printf("Store pointer location %p\n", *store); + + return amount; + +error: + return -1; +} + #ifdef DEBUG_SOCKET void socket_debug() { @@ -219,6 +265,7 @@ int _socket(pid_t pid, int domain, int type, int protocol) } sock->type = type; + sock->family = domain; family = families[domain]; @@ -495,9 +542,11 @@ int _recvmsg(pid_t pid, int socket, struct msghdr *msg, int flags) return -EBADF; } + pthread_rwlock_rdlock(&slock); socket_rd_acquire(sock); int rc = sock->ops->recvmsg(sock, msg, flags); socket_release(sock); - + pthread_rwlock_unlock(&slock); + return rc; } diff --git a/src/tuntap_if.c b/src/tuntap_if.c index 817deac..7bcbec7 100644 --- a/src/tuntap_if.c +++ b/src/tuntap_if.c @@ -35,7 +35,7 @@ static int tun_alloc(char *dev) if( (fd = open("/dev/net/tap", O_RDWR)) < 0 ) { perror("Cannot open TUN/TAP dev\n" "Make sure one exists with " - "'$ mknod /dev/net/tap c 10 200'"); + "'mknod /dev/net/tap c 10 200'"); exit(1); } From dff72722485142c9ada2f25a34e7f254bc4f84b1 Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Wed, 10 Apr 2019 08:36:23 +0300 Subject: [PATCH 23/35] Free allocated sock_diag memory properly --- src/netlink.c | 28 ++++++++++++++++++++++++++-- src/socket.c | 3 +-- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/netlink.c b/src/netlink.c index d5bd888..5a0d141 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -345,11 +345,35 @@ int process_netlink_request_tcp(struct nlmsghdr *nl, struct nl_message *req) printf("Pointer memory location %p\n", tmp); + struct + { + struct nlmsghdr nlh; + struct inet_diag_msg idm; + struct nlattr nla; + uint8_t flag; + } resp[rc]; + + int size = 0; + for (int i = 0; i < rc; i++) { - printf("received inet_diag_msg %d\n", tmp[i].idiag_family); + resp->nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY; + resp->nlh.nlmsg_flags = NLM_F_MULTI; + resp->nlh.nlmsg_seq = 123456; + resp->nlh.nlmsg_pid = 0; + resp->nla.nla_len = 5; + resp->nla.nla_type = INET_DIAG_SHUTDOWN; + resp->flag = 0; + + memcpy(&resp->idm, (tmp + i), sizeof(struct inet_diag_msg)); + + size += sizeof(resp); } - return rc; + if (tmp != NULL) { + free(tmp); + } + + return size; } int process_netlink_request_not_supported(struct nlmsghdr *nl, struct nl_message *req) diff --git a/src/socket.c b/src/socket.c index e8a9ced..3e440ea 100644 --- a/src/socket.c +++ b/src/socket.c @@ -208,7 +208,7 @@ int filter_sockets(int family, int proto, uint8_t **store, goto error; } - rc = f(sock, *store); + rc = f(sock, (*store + (rc * amount))); if (rc < 0) { perror("Failed on socket filtering"); @@ -216,7 +216,6 @@ int filter_sockets(int family, int proto, uint8_t **store, } amount++; - store += rc; } } From b4fd7206ec6cdc5f4ec680bc47730a187585c186 Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Fri, 12 Apr 2019 10:15:04 +0300 Subject: [PATCH 24/35] Consume Netlink request after use --- include/syshead.h | 1 + src/netlink.c | 87 ++++++++++++++++++++++++++++++++--------------- 2 files changed, 61 insertions(+), 27 deletions(-) diff --git a/include/syshead.h b/include/syshead.h index 63aac83..e3ffdd6 100644 --- a/include/syshead.h +++ b/include/syshead.h @@ -1,6 +1,7 @@ #ifndef SYSHEAD_H #define SYSHEAD_H +#include #include #include #include diff --git a/src/netlink.c b/src/netlink.c index 5a0d141..6cf7cf5 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -56,6 +56,27 @@ struct nl_message *alloc_message(struct socket *sock, const struct nlmsghdr *nl, return nlmsg; } +int message_free(struct nl_message *nlm) +{ + int rc = pthread_rwlock_wrlock(&mlock); + + if (rc != 0) { + perror("Could not acquire message lock"); + return rc; + } + + list_del(&nlm->list); + message_amount--; + + rc = pthread_rwlock_unlock(&mlock); + if (rc != 0) { + perror("Could not release message lock"); + return rc; + } + + return rc; +} + int netlink_create(struct socket *sock, int protocol) { struct sock *sk; @@ -314,6 +335,8 @@ int convert_socket_to_inet_tcp_diag_msg(struct socket *s, uint8_t *ptr) { struct inet_diag_msg *idm = (struct inet_diag_msg *) ptr; + memset(ptr, 0, sizeof(struct inet_diag_msg)); + idm->idiag_family = AF_INET; idm->idiag_state = TCP_ESTABLISHED; idm->idiag_timer = 0; @@ -323,6 +346,8 @@ int convert_socket_to_inet_tcp_diag_msg(struct socket *s, uint8_t *ptr) idm->idiag_wqueue = 0; idm->idiag_uid = 0; idm->idiag_inode = 0; + idm->id.idiag_sport = htons(1337); + idm->id.idiag_dport = htons(1337); return sizeof(struct inet_diag_msg); } @@ -330,10 +355,6 @@ int convert_socket_to_inet_tcp_diag_msg(struct socket *s, uint8_t *ptr) int process_netlink_request_tcp(struct nlmsghdr *nl, struct nl_message *req) { - struct inet_diag_msg *idm = (struct inet_diag_msg *)(nl + sizeof(struct nlmsghdr)); - //struct sock_diag_req *sdr = (struct sock_diag_req *)(req->data); - idm->idiag_family = AF_INET; - struct inet_diag_msg *tmp = NULL; int rc = filter_sockets(AF_INET, IPPROTO_TCP, (uint8_t **)&tmp, convert_socket_to_inet_tcp_diag_msg, sizeof(struct inet_diag_msg)); @@ -343,20 +364,19 @@ int process_netlink_request_tcp(struct nlmsghdr *nl, struct nl_message *req) return -1; } - printf("Pointer memory location %p\n", tmp); - struct { struct nlmsghdr nlh; struct inet_diag_msg idm; struct nlattr nla; - uint8_t flag; + uint32_t flag; } resp[rc]; - int size = 0; + size_t size = sizeof(struct nlmsghdr) + sizeof(struct inet_diag_msg) + sizeof(struct nlattr) + sizeof(uint32_t); for (int i = 0; i < rc; i++) { resp->nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY; + resp->nlh.nlmsg_len = size; resp->nlh.nlmsg_flags = NLM_F_MULTI; resp->nlh.nlmsg_seq = 123456; resp->nlh.nlmsg_pid = 0; @@ -365,15 +385,15 @@ int process_netlink_request_tcp(struct nlmsghdr *nl, struct nl_message *req) resp->flag = 0; memcpy(&resp->idm, (tmp + i), sizeof(struct inet_diag_msg)); - - size += sizeof(resp); } + memcpy(nl, resp, sizeof(resp)); + if (tmp != NULL) { free(tmp); } - return size; + return size * rc; } int process_netlink_request_not_supported(struct nlmsghdr *nl, struct nl_message *req) @@ -385,6 +405,10 @@ int demux_netlink_request(struct nlmsghdr *nl, struct nl_message *req, int flags { int rc = -1; + if (req == NULL) { + return 0; + } + struct sock_diag_req *sdr = (struct sock_diag_req *)req->data; switch (sdr->sdiag_family) { @@ -394,29 +418,24 @@ int demux_netlink_request(struct nlmsghdr *nl, struct nl_message *req, int flags rc = process_netlink_request_tcp(nl, req); break; default: + print_err("Not supported sdiag_protocol: %d\n", sdr->sdiag_protocol); rc = process_netlink_request_not_supported(nl, req); break; } break; default: + print_err("Not supported sdiag_family: %d\n", sdr->sdiag_family); rc = process_netlink_request_not_supported(nl, req); break; } - - if (flags & (MSG_PEEK | MSG_TRUNC)) { - // Empty out msg_iov contents - nl->nlmsg_flags = MSG_TRUNC; - return rc; - } - // Remove nl_message from list - nl->nlmsg_len = 20; - nl->nlmsg_type = NLMSG_DONE; - nl->nlmsg_flags = NLM_F_MULTI; - nl->nlmsg_seq = 123456; - nl->nlmsg_pid = 0; + if (!(flags & (MSG_PEEK | MSG_TRUNC))) { + // Request has been consumed, delete it + assert(message_free(req) == 0); + } printf("Returning nlmsghdr: nlmsg_type DONE %d, flags MULTI %d\n", nl->nlmsg_type & NLMSG_DONE, nl->nlmsg_flags & NLM_F_MULTI); + printf("Rc %d\n", rc); return rc; } @@ -438,12 +457,26 @@ int netlink_recvmsg(struct socket *sock, struct msghdr *message, int flags) struct nl_message *nlm = find_netlink_request(sock->fd); - if (nlm == NULL) { - return -EBADF; - } - int rc = demux_netlink_request(nl, nlm, flags); + if (rc == 0) { + rc = 20; + } + + if (flags & (MSG_PEEK | MSG_TRUNC)) { + // Empty out msg_iov contents + nl->nlmsg_flags = MSG_TRUNC; + return rc; + } + + if (rc == 20) { + nl->nlmsg_len = 20; + nl->nlmsg_type = NLMSG_DONE; + nl->nlmsg_flags = NLM_F_MULTI; + nl->nlmsg_seq = 123456; + nl->nlmsg_pid = 0; + } + v->iov_len = rc; return rc; From 894d7b11b580756ed04836394e86da5370898fb3 Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Fri, 12 Apr 2019 10:31:59 +0300 Subject: [PATCH 25/35] Make `ss` print proper idiag_state This is the order Linux header uses, so let's switch to it. --- include/tcp.h | 20 ++++++++++---------- src/netlink.c | 1 + 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/include/tcp.h b/include/tcp.h index 34f5d86..15fe390 100644 --- a/include/tcp.h +++ b/include/tcp.h @@ -142,33 +142,33 @@ struct tcpiphdr { } __attribute__((packed)); enum tcp_states { - TCP_LISTEN, /* represents waiting for a connection request from any remote - TCP and port. */ + TCP_ESTABLISHED = 1, /* represents an open connection, data received can be + delivered to the user. The normal state for the data transfer phase + of the connection. */ TCP_SYN_SENT, /* represents waiting for a matching connection request after having sent a connection request. */ TCP_SYN_RECEIVED, /* represents waiting for a confirming connection request acknowledgment after having both received and sent a connection request. */ - TCP_ESTABLISHED, /* represents an open connection, data received can be - delivered to the user. The normal state for the data transfer phase - of the connection. */ TCP_FIN_WAIT_1, /* represents waiting for a connection termination request from the remote TCP, or an acknowledgment of the connection termination request previously sent. */ TCP_FIN_WAIT_2, /* represents waiting for a connection termination request from the remote TCP. */ + TCP_TIME_WAIT, /* represents waiting for enough time to pass to be sure + the remote TCP received the acknowledgment of its connection + termination request. */ TCP_CLOSE, /* represents no connection state at all. */ TCP_CLOSE_WAIT, /* represents waiting for a connection termination request from the local user. */ - TCP_CLOSING, /* represents waiting for a connection termination request - acknowledgment from the remote TCP. */ TCP_LAST_ACK, /* represents waiting for an acknowledgment of the connection termination request previously sent to the remote TCP (which includes an acknowledgment of its connection termination request). */ - TCP_TIME_WAIT, /* represents waiting for enough time to pass to be sure - the remote TCP received the acknowledgment of its connection - termination request. */ + TCP_LISTEN, /* represents waiting for a connection request from any remote + TCP and port. */ + TCP_CLOSING, /* represents waiting for a connection termination request + acknowledgment from the remote TCP. */ }; struct tcb { diff --git a/src/netlink.c b/src/netlink.c index 6cf7cf5..50a6479 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -348,6 +348,7 @@ int convert_socket_to_inet_tcp_diag_msg(struct socket *s, uint8_t *ptr) idm->idiag_inode = 0; idm->id.idiag_sport = htons(1337); idm->id.idiag_dport = htons(1337); + idm->id.idiag_if = 0; return sizeof(struct inet_diag_msg); } From 4ba870267e94ea57b3bca2832e5d86d17b2f17c7 Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Tue, 23 Apr 2019 08:44:56 +0300 Subject: [PATCH 26/35] Grab proper port and address info from TCPv4 socket --- src/netlink.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/netlink.c b/src/netlink.c index 50a6479..81451a0 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -338,7 +338,7 @@ int convert_socket_to_inet_tcp_diag_msg(struct socket *s, uint8_t *ptr) memset(ptr, 0, sizeof(struct inet_diag_msg)); idm->idiag_family = AF_INET; - idm->idiag_state = TCP_ESTABLISHED; + idm->idiag_state = s->sk->state; idm->idiag_timer = 0; idm->idiag_retrans = 0; idm->idiag_expires = 0; @@ -346,8 +346,10 @@ int convert_socket_to_inet_tcp_diag_msg(struct socket *s, uint8_t *ptr) idm->idiag_wqueue = 0; idm->idiag_uid = 0; idm->idiag_inode = 0; - idm->id.idiag_sport = htons(1337); - idm->id.idiag_dport = htons(1337); + idm->id.idiag_sport = htons(s->sk->sport); + idm->id.idiag_dport = htons(s->sk->dport); + idm->id.idiag_src[0] = htonl(s->sk->saddr); + idm->id.idiag_dst[0] = htonl(s->sk->daddr); idm->id.idiag_if = 0; return sizeof(struct inet_diag_msg); From 4220ab67f32939bcc9bc8b835fce0597a5b1a466 Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Thu, 25 Apr 2019 08:15:28 +0300 Subject: [PATCH 27/35] Use socket type for filtering This is more accurate than protocol, since e.g. SOCK_STREAM implies TCP --- src/netlink.c | 22 +++++++++++----------- src/socket.c | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/netlink.c b/src/netlink.c index 81451a0..f609dbf 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -360,7 +360,7 @@ int process_netlink_request_tcp(struct nlmsghdr *nl, struct nl_message *req) struct inet_diag_msg *tmp = NULL; - int rc = filter_sockets(AF_INET, IPPROTO_TCP, (uint8_t **)&tmp, convert_socket_to_inet_tcp_diag_msg, sizeof(struct inet_diag_msg)); + int rc = filter_sockets(AF_INET, SOCK_STREAM, (uint8_t **)&tmp, convert_socket_to_inet_tcp_diag_msg, sizeof(struct inet_diag_msg)); if (rc < 0) { perror("Failed on netlink TCP processing"); @@ -378,16 +378,16 @@ int process_netlink_request_tcp(struct nlmsghdr *nl, struct nl_message *req) size_t size = sizeof(struct nlmsghdr) + sizeof(struct inet_diag_msg) + sizeof(struct nlattr) + sizeof(uint32_t); for (int i = 0; i < rc; i++) { - resp->nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY; - resp->nlh.nlmsg_len = size; - resp->nlh.nlmsg_flags = NLM_F_MULTI; - resp->nlh.nlmsg_seq = 123456; - resp->nlh.nlmsg_pid = 0; - resp->nla.nla_len = 5; - resp->nla.nla_type = INET_DIAG_SHUTDOWN; - resp->flag = 0; - - memcpy(&resp->idm, (tmp + i), sizeof(struct inet_diag_msg)); + resp[i].nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY; + resp[i].nlh.nlmsg_len = size; + resp[i].nlh.nlmsg_flags = NLM_F_MULTI; + resp[i].nlh.nlmsg_seq = 123456; + resp[i].nlh.nlmsg_pid = 0; + resp[i].nla.nla_len = 5; + resp[i].nla.nla_type = INET_DIAG_SHUTDOWN; + resp[i].flag = 0; + + memcpy(&resp[i].idm, (tmp + i), sizeof(struct inet_diag_msg)); } memcpy(nl, resp, sizeof(resp)); diff --git a/src/socket.c b/src/socket.c index 3e440ea..af88572 100644 --- a/src/socket.c +++ b/src/socket.c @@ -184,7 +184,7 @@ struct socket *socket_find(struct socket *find) return sock; } -int filter_sockets(int family, int proto, uint8_t **store, +int filter_sockets(int family, int type, uint8_t **store, int (*f)(struct socket *s, uint8_t *ptr), int size) { struct list_head *item; @@ -199,7 +199,7 @@ int filter_sockets(int family, int proto, uint8_t **store, list_for_each(item, &sockets) { sock = list_entry(item, struct socket, list); - if (sock->family == family && sock->sk->protocol == proto) { + if (sock->family == family && sock->type == type) { allocated += size; *store = realloc(*store, allocated); From c84b0caf42ed867e53c1b8e8bd71a8e71f3b4103 Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Thu, 25 Apr 2019 09:13:00 +0300 Subject: [PATCH 28/35] Add note about possible false deadlock detected by TSan --- src/inet.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/inet.c b/src/inet.c index 61a940d..224fd0a 100644 --- a/src/inet.c +++ b/src/inet.c @@ -113,6 +113,8 @@ static int inet_stream_connect(struct socket *sock, const struct sockaddr *addr, goto out; } + // False thread deadlock detected here by TSan? + // See commit c60d98322964976439ad4f09344de2989131d091 pthread_mutex_lock(&sock->sleep.lock); while (sock->state == SS_CONNECTING && sk->err == -EINPROGRESS) { socket_release(sock); @@ -120,7 +122,6 @@ static int inet_stream_connect(struct socket *sock, const struct sockaddr *addr, socket_wr_acquire(sock); } pthread_mutex_unlock(&sock->sleep.lock); - socket_wr_acquire(sock); switch (sk->err) { case -ETIMEDOUT: From 3fa611c949f71925239545d893d9c1998f926500 Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Fri, 26 Apr 2019 09:38:08 +0300 Subject: [PATCH 29/35] Delete debug printfs --- src/ipc.c | 4 ---- src/netlink.c | 11 ----------- src/socket.c | 4 ---- 3 files changed, 19 deletions(-) diff --git a/src/ipc.c b/src/ipc.c index 17355b7..68eb3ad 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -480,8 +480,6 @@ static int ipc_recvmsg(int sockfd, struct ipc_msg *msg) rc = _recvmsg(pid, payload->sockfd, &message, payload->flags); - printf("ipc msg len is now %d\n", payload->msg_iovlen); - int iovlen = 0; for (int i = 0; i < payload->msg_iovlen; i++) { @@ -504,8 +502,6 @@ static int ipc_recvmsg(int sockfd, struct ipc_msg *msg) error->rc = rc < 0 ? -1 : rc; error->err = rc < 0 ? -rc : 0; - printf("IPC recvmsg sending %d bytes\n", resplen); - if (ipc_try_send(sockfd, (char *)response, resplen) == -1) { perror("Error on writing IPC recvmsg response"); } diff --git a/src/netlink.c b/src/netlink.c index f609dbf..1974f1f 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -286,8 +286,6 @@ int netlink_sendmsg(struct socket *sock, const struct msghdr *message, int flags int rc = 0; struct nl_message *nlmsg; - printf("Netlink message amount %d\n", message_amount); - for (int i = 0; imsg_iovlen; i++) { struct iovec *v = &message->msg_iov[i]; struct nlmsghdr *nl = v->iov_base; @@ -300,12 +298,6 @@ int netlink_sendmsg(struct socket *sock, const struct msghdr *message, int flags message_amount++; pthread_rwlock_unlock(&mlock); - printf("nl len %d, nl type %d, nl flags %d\n", nl->nlmsg_len, nl->nlmsg_type, nl->nlmsg_flags); - printf("nl pid %d, nl seq %d\n", nl->nlmsg_pid, nl->nlmsg_seq); - printf("sdr family %d, proto %d\n", sdr->sdiag_family, sdr->sdiag_protocol); - - printf("type is sock_diag %d\n", nl->nlmsg_type == SOCK_DIAG_BY_FAMILY); - printf("type is sock_diag %d\n", 1 == 1); rc += nl->nlmsg_len; } @@ -437,9 +429,6 @@ int demux_netlink_request(struct nlmsghdr *nl, struct nl_message *req, int flags assert(message_free(req) == 0); } - printf("Returning nlmsghdr: nlmsg_type DONE %d, flags MULTI %d\n", nl->nlmsg_type & NLMSG_DONE, nl->nlmsg_flags & NLM_F_MULTI); - printf("Rc %d\n", rc); - return rc; } diff --git a/src/socket.c b/src/socket.c index af88572..d085ef4 100644 --- a/src/socket.c +++ b/src/socket.c @@ -219,10 +219,6 @@ int filter_sockets(int family, int type, uint8_t **store, } } - printf("Iterated through sockets %d\n", amount); - - printf("Store pointer location %p\n", *store); - return amount; error: From e6f531faf09322dc814674ae5f016261c46274ec Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Fri, 26 Apr 2019 09:45:30 +0300 Subject: [PATCH 30/35] Start as root but change to uid `nobody` before starting stack This change is introduced because suddenly CAP_NET_ADMIN stopped working for my Arch Linux. In essence, doing $ sudo setcap cap_net_admin=ep $(which ip) Has no effect anymore: $ ip link set dev tap0 up RTNETLINK answers: Operation not permitted Searching the Internet, one error case is if the directory is mounted with `nosuid`, but this does not seem to be the case in my Linux. --- Documentation/getting-started.md | 21 +++++++-------------- Makefile | 3 --- src/main.c | 16 ++++++++++++++++ tests/utils/common | 2 +- 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/Documentation/getting-started.md b/Documentation/getting-started.md index f388b60..c895e6d 100644 --- a/Documentation/getting-started.md +++ b/Documentation/getting-started.md @@ -12,13 +12,7 @@ Standard `make` stuff. make all -This builds `lvl-ip` itself, but also the libc wrapper and provided example applications. - -When building, `sudo setcap ...` probably asks super user permissions from you. This is because `lvl-ip` needs the `CAP_NET_ADMIN` capability to setup itself. After the setup, it drops that capability. - -Currently, `lvl-ip` also configures the tap interface through the `ip` tool. Hence, give it permissions too: - - sudo setcap cap_net_admin=ep $(which ip) +This builds `lvl-ip` and the libc wrapper (under `tools/`) and provided example applications (under `apps/`). # Setup @@ -45,9 +39,13 @@ See http://www.netfilter.org/documentation/HOWTO/packet-filtering-HOWTO-9.html f When you've built lvl-ip and setup your host stack to forward packets, you can try communicating to the Internet: - ./lvl-ip + sudo ./lvl-ip -The userspace TCP/IP stack should start. Now, first test communications with the provided applications: +(Super-user privileges are needed for configuring the tap interface, but the privileges are dropped before the TCP stack starts.) + +The userspace TCP/IP stack should start. + +Now, first test communications with the provided applications: cd tools ./level-ip ../apps/curl/curl google.com 80 @@ -56,10 +54,6 @@ The userspace TCP/IP stack should start. Now, first test communications with the The important point is that `./level-ip` aims to be usable against any existing dynamically-linked application. Let's try the _real_ `curl`: - [saminiir@localhost tools]$ curl --version - curl 7.50.0 (x86_64-pc-linux-gnu) libcurl/7.50.0 OpenSSL/1.0.2h zlib/1.2.8 libidn/1.33 libssh2/1.7.0 - Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp - Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP UnixSockets [saminiir@localhost tools]$ curl google.com 302 Moved @@ -88,7 +82,6 @@ Try browsing the Web, with Level-IP doing the packet transfer: That's it! - # Troubleshooting Common errors: diff --git a/Makefile b/Makefile index ae9882e..bf30a7d 100644 --- a/Makefile +++ b/Makefile @@ -7,9 +7,6 @@ apps = apps/curl/curl lvl-ip: $(obj) $(CC) $(CFLAGS) $(CPPFLAGS) $(obj) -o lvl-ip - @echo - @echo "lvl-ip needs CAP_NET_ADMIN:" - sudo setcap cap_setpcap,cap_net_admin=ep lvl-ip build/%.o: src/%.c ${headers} $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ diff --git a/src/main.c b/src/main.c index 9376ce2..d0be336 100644 --- a/src/main.c +++ b/src/main.c @@ -118,6 +118,22 @@ void init_security() perror("Error on capability set drop"); exit(1); } + + // 65534 should be `nobody` according to http://www.linfo.org/uid.html + if (setgid(65534) != 0) { + perror("Error on changing gid"); + exit(1); + } + + if (setuid(65534) != 0) { + perror("Error on changing uid"); + exit(1); + } + + if (getuid() == 0 || getgid() == 0) { + print_err("Error on dropping root privileges\n"); + exit(1); + } } int main(int argc, char** argv) diff --git a/tests/utils/common b/tests/utils/common index 36b4d3e..a8140a0 100755 --- a/tests/utils/common +++ b/tests/utils/common @@ -6,7 +6,7 @@ repo="$(git rev-parse --show-toplevel)" folder="$(dirname $0)" function start_stack { - "$repo/lvl-ip" > ../lvl-ip-test.log 2>&1 & + sudo "$repo/lvl-ip" > ../lvl-ip-test.log 2>&1 & stackip="$!" for i in {1..3}; do From 72e4c27e6313d58bc4a173fc075532073dedeb78 Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Fri, 26 Apr 2019 09:56:50 +0300 Subject: [PATCH 31/35] Killall lvl-ip processes after test suite --- tests/test-run-all | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-run-all b/tests/test-run-all index fe9a0e9..40a2e77 100755 --- a/tests/test-run-all +++ b/tests/test-run-all @@ -5,7 +5,7 @@ set -eu source "utils/common" function teardown { - kill "$stackip" + sudo killall lvl-ip } trap teardown EXIT ERR From b7f38f89fd92c6f9be086e33c8271175e1fb075a Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Sun, 28 Apr 2019 11:09:00 +0300 Subject: [PATCH 32/35] Print lvl-ip logs on test failure --- tests/utils/common | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/utils/common b/tests/utils/common index a8140a0..a5c51b0 100755 --- a/tests/utils/common +++ b/tests/utils/common @@ -26,6 +26,7 @@ function test_pass { function test_fail { echo -e "\t$2 Test fail: $1" 2>&1 + cat ../lvl-ip-test.log exit 1 } From f9d118f49a849c81f767e135bfc0dc3f44ceb796 Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Wed, 8 May 2019 08:18:20 +0300 Subject: [PATCH 33/35] Manually create tap device Since iproute2 changed its capability handling, seems like it is simpler to just guide the user to create the tap device itself. This is also what Google's Netstack does. https://github.com/shemminger/iproute2/commit/9b13cc98f5952f62b825461727c8170d37a4037d --- .travis.yml | 4 +++- Documentation/getting-started.md | 11 ++++------- src/cli.c | 1 - src/main.c | 30 ---------------------------- src/tuntap_if.c | 34 +++----------------------------- 5 files changed, 10 insertions(+), 70 deletions(-) diff --git a/.travis.yml b/.travis.yml index dc1e019..76153f4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,5 +12,7 @@ before_install: script: - sudo mknod /dev/net/tap c 10 200 - sudo chmod 0666 /dev/net/tap - - sudo setcap cap_net_admin=ep /bin/ip + - sudo ip tuntap add mode tap tap0 + - sudo ip link set dev tap0 up + - sudo ip addr add 10.0.0.5/24 dev tap0 - make test diff --git a/Documentation/getting-started.md b/Documentation/getting-started.md index c895e6d..a3bb592 100644 --- a/Documentation/getting-started.md +++ b/Documentation/getting-started.md @@ -20,6 +20,9 @@ Level-IP uses a Linux TAP device to communicate to the outside world. In short, sudo mknod /dev/net/tap c 10 200 sudo chmod 0666 /dev/net/tap + sudo ip tuntap add mode tap tap0 + sudo ip link set dev tap0 up + sudo ip addr add 10.0.0.5/24 dev tap0 In essence, `lvl-ip` operates as a host inside the tap device's subnet. Therefore, in order to communicate with other hosts, the tap device needs to be set in a forwarding mode: @@ -39,9 +42,7 @@ See http://www.netfilter.org/documentation/HOWTO/packet-filtering-HOWTO-9.html f When you've built lvl-ip and setup your host stack to forward packets, you can try communicating to the Internet: - sudo ./lvl-ip - -(Super-user privileges are needed for configuring the tap interface, but the privileges are dropped before the TCP stack starts.) + ./lvl-ip The userspace TCP/IP stack should start. @@ -101,7 +102,3 @@ $ modprobe tun ``` Otherwise, consult your distro's documentation on setting it up. - -## Missing capabilities for Level-IP - -`lvl-ip` requires the `CAP_NET_ADMIN` capability to bind to the tap device. diff --git a/src/cli.c b/src/cli.c index 3574b6c..e8e6886 100644 --- a/src/cli.c +++ b/src/cli.c @@ -9,7 +9,6 @@ static void usage(char *app) print_err("Usage: %s\n", app); print_err("\n"); print_err("Linux TCP/IP stack implemented with TUN/TAP devices.\n"); - print_err("Requires the CAP_NET_ADMIN capability. See capabilities(7).\n"); print_err("See https://www.kernel.org/doc/Documentation/networking/tuntap.txt\n"); print_err("\n"); print_err("Options:\n"); diff --git a/src/main.c b/src/main.c index d0be336..e2be991 100644 --- a/src/main.c +++ b/src/main.c @@ -107,42 +107,12 @@ void free_stack() free_tun(); } -void init_security() -{ - if (prctl(PR_CAPBSET_DROP, CAP_NET_ADMIN) == -1) { - perror("Error on network admin capability drop"); - exit(1); - } - - if (prctl(PR_CAPBSET_DROP, CAP_SETPCAP) == -1) { - perror("Error on capability set drop"); - exit(1); - } - - // 65534 should be `nobody` according to http://www.linfo.org/uid.html - if (setgid(65534) != 0) { - perror("Error on changing gid"); - exit(1); - } - - if (setuid(65534) != 0) { - perror("Error on changing uid"); - exit(1); - } - - if (getuid() == 0 || getgid() == 0) { - print_err("Error on dropping root privileges\n"); - exit(1); - } -} - int main(int argc, char** argv) { parse_cli(argc, argv); init_signals(); init_stack(); - init_security(); run_threads(); wait_for_threads(); diff --git a/src/tuntap_if.c b/src/tuntap_if.c index 7bcbec7..0cb3408 100644 --- a/src/tuntap_if.c +++ b/src/tuntap_if.c @@ -9,21 +9,6 @@ char *tapaddr = "10.0.0.5"; char *cidr = "10.0.0.5/24"; char *taproute = "10.0.0.0/24"; -static int set_if_route(char *dev, char *cidr) -{ - return run_cmd("ip route add dev %s %s", dev, cidr); -} - -static int set_if_address(char *dev, char *cidr) -{ - return run_cmd("ip address add dev %s local %s", dev, cidr); -} - -static int set_if_up(char *dev) -{ - return run_cmd("ip link set dev %s up", dev); -} - /* * Taken from Kernel Documentation/networking/tuntap.txt */ @@ -48,6 +33,7 @@ static int tun_alloc(char *dev) */ ifr.ifr_flags = IFF_TAP | IFF_NO_PI; if( *dev ) { + printf("dev is %s\n", dev); strncpy(ifr.ifr_name, dev, IFNAMSIZ); } @@ -56,8 +42,7 @@ static int tun_alloc(char *dev) close(fd); return err; } - - strcpy(dev, ifr.ifr_name); + return fd; } @@ -73,20 +58,7 @@ int tun_write(char *buf, int len) void tun_init() { - dev = calloc(10, 1); - tun_fd = tun_alloc(dev); - - if (set_if_up(dev) != 0) { - print_err("ERROR when setting up if\n"); - } - - if (set_if_route(dev, taproute) != 0) { - print_err("ERROR when setting route for if\n"); - } - - if (set_if_address(dev, cidr) != 0) { - print_err("ERROR when setting addr for if\n"); - } + tun_fd = tun_alloc("tap0"); } void free_tun() From 34b227c4c26de7c4ef380eaa34445eb9b3a89c31 Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Wed, 8 May 2019 08:20:01 +0300 Subject: [PATCH 34/35] Revert "Killall lvl-ip processes after test suite" This reverts commit 72e4c27e6313d58bc4a173fc075532073dedeb78. --- tests/test-run-all | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-run-all b/tests/test-run-all index 40a2e77..fe9a0e9 100755 --- a/tests/test-run-all +++ b/tests/test-run-all @@ -5,7 +5,7 @@ set -eu source "utils/common" function teardown { - sudo killall lvl-ip + kill "$stackip" } trap teardown EXIT ERR From 9b7d7aac803ca3806207215d9aa514d6dab87c84 Mon Sep 17 00:00:00 2001 From: Sami Niiranen Date: Thu, 9 May 2019 08:31:55 +0300 Subject: [PATCH 35/35] Add more descriptive error messages on IPC socket init errors --- src/ipc.c | 7 ++++--- src/tuntap_if.c | 1 - 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ipc.c b/src/ipc.c index 68eb3ad..408c173 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -586,7 +586,7 @@ void *start_ipc_listener() } if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { - exit_with_error(fd, "IPC listener UNIX socket"); + exit_with_error(fd, "Unable to create IPC UNIX socket"); } memset(&un, 0, sizeof(struct sockaddr_un)); @@ -594,11 +594,12 @@ void *start_ipc_listener() strncpy(un.sun_path, sockname, sizeof(un.sun_path) - 1); if ((rc = bind(fd, (const struct sockaddr *) &un, sizeof(struct sockaddr_un))) == -1) { - exit_with_error(rc, "IPC bind"); + print_err("Check socket file permissions: %s\n", sockname); + exit_with_error(rc, "Unable to bind to IPC socket"); } if ((rc = listen(fd, 20)) == -1) { - exit_with_error(rc, "IPC listen"); + exit_with_error(rc, "Unable to listen on IPC socket"); } if ((rc = chmod(sockname, S_IRUSR | S_IWUSR | S_IXUSR | diff --git a/src/tuntap_if.c b/src/tuntap_if.c index 0cb3408..8aaaf9d 100644 --- a/src/tuntap_if.c +++ b/src/tuntap_if.c @@ -33,7 +33,6 @@ static int tun_alloc(char *dev) */ ifr.ifr_flags = IFF_TAP | IFF_NO_PI; if( *dev ) { - printf("dev is %s\n", dev); strncpy(ifr.ifr_name, dev, IFNAMSIZ); }