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 a6377d6..a3bb592 100644
--- a/Documentation/getting-started.md
+++ b/Documentation/getting-started.md
@@ -10,34 +10,29 @@ 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.
-
-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:
-
- $ which ip
- /usr/bin/ip
- $ sudo setcap cap_net_admin=ep /usr/bin/ip
+This builds `lvl-ip` and the libc wrapper (under `tools/`) and provided example applications (under `apps/`).
# 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
+ 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:
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,21 +42,19 @@ 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:
+The userspace TCP/IP stack should start.
- $ cd tools
- $ ./level-ip ../apps/curl/curl google.com 80
+Now, first test communications with the provided applications:
+
+ 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.
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
@@ -89,3 +82,23 @@ 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.
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/include/ipc.h b/include/ipc.h
index 4ae0ff9..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)
@@ -26,6 +26,8 @@ void *start_ipc_listener();
#define IPC_SETSOCKOPT 0x0009
#define IPC_GETPEERNAME 0x000A
#define IPC_GETSOCKNAME 0x000B
+#define IPC_SENDMSG 0x000C
+#define IPC_RECVMSG 0x000D
struct ipc_thread {
struct list_head list;
@@ -105,4 +107,18 @@ struct ipc_sockname {
uint8_t sa_data[128];
};
+struct ipc_msghdr {
+ int sockfd;
+ 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
new file mode 100644
index 0000000..b4024a4
--- /dev/null
+++ b/include/netlink.h
@@ -0,0 +1,40 @@
+#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
+
+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);
+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);
+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);
+#endif
diff --git a/include/socket.h b/include/socket.h
index f9db44f..5b1f7fa 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, const struct msghdr *message, int flags);
+ int (*recvmsg) (struct socket *sock, struct msghdr *message, int flags);
};
struct net_family {
@@ -62,6 +64,7 @@ struct socket {
pid_t pid;
int refcnt;
enum socket_state state;
+ int family;
short type;
int flags;
struct sock *sk;
@@ -83,9 +86,13 @@ 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);
+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/include/syshead.h b/include/syshead.h
index 0f2cc23..e3ffdd6 100644
--- a/include/syshead.h
+++ b/include/syshead.h
@@ -1,6 +1,7 @@
#ifndef SYSHEAD_H
#define SYSHEAD_H
+#include
#include
#include
#include
@@ -13,6 +14,9 @@
#include
#include
#include
+#include
+#include
+#include
#include
#include
#include
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/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/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/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:
diff --git a/src/ipc.c b/src/ipc.c
index 8e149e1..408c173 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);
@@ -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);
}
@@ -226,7 +231,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 +245,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 +256,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);
}
@@ -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) {
@@ -294,7 +301,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;
@@ -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");
@@ -332,7 +339,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 +349,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 +381,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 +391,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,43 +403,146 @@ static int ipc_getsockname(int sockfd, struct ipc_msg *msg)
return rc;
}
+int deserialize_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;
+}
+
+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;
+ pid_t pid = msg->pid;
+ int rc = -1;
+
+ struct msghdr message;
+ struct iovec iov[payload->msg_iovlen];
+
+ deserialize_msghdr(payload, &message, iov);
+
+ rc = _sendmsg(pid, payload->sockfd, &message, payload->flags);
+
+ 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;
+
+ struct msghdr message;
+ struct iovec iov[payload->msg_iovlen];
+
+ deserialize_msghdr(payload, &message, iov);
+
+ rc = _recvmsg(pid, payload->sockfd, &message, payload->flags);
+
+ 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) + 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)
{
struct ipc_msg *msg = (struct ipc_msg *)cmdbuf;
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);
- 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);
+ case IPC_RECVMSG:
+ return ipc_recvmsg(sockfd, msg);
+ default:
+ print_err("No such IPC type %d\n", msg->type);
+ break;
};
-
+
return 0;
}
@@ -457,7 +567,7 @@ void *socket_ipc_open(void *args) {
if (rc == -1) {
perror("socket ipc read");
}
-
+
return NULL;
}
@@ -468,55 +578,45 @@ 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) {
- perror("IPC listener UNIX socket");
- exit(EXIT_FAILURE);
+ exit_with_error(fd, "Unable to create IPC 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) {
+ print_err("Check socket file permissions: %s\n", sockname);
+ exit_with_error(rc, "Unable to bind to IPC socket");
}
- rc = listen(fd, 20);
-
- if (rc == -1) {
- perror("IPC listen");
- exit(EXIT_FAILURE);
+ if ((rc = listen(fd, 20)) == -1) {
+ exit_with_error(rc, "Unable to listen on IPC socket");
}
- 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");
};
}
diff --git a/src/main.c b/src/main.c
index 9376ce2..e2be991 100644
--- a/src/main.c
+++ b/src/main.c
@@ -107,26 +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);
- }
-}
-
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/netlink.c b/src/netlink.c
new file mode 100644
index 0000000..1974f1f
--- /dev/null
+++ b/src/netlink.c
@@ -0,0 +1,475 @@
+#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 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,
+};
+
+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,
+ .sendmsg = &netlink_sendmsg,
+ .recvmsg = &netlink_recvmsg,
+};
+
+static struct sock_type netlink_ops[] = {
+ {
+ .sock_ops = &netlink_stream_ops,
+ .net_ops = &tcp_ops,
+ .type = SOCK_STREAM,
+ .protocol = IPPROTO_TCP,
+ }
+};
+
+struct nl_message *alloc_message(struct socket *sock, const struct nlmsghdr *nl, void *payload, int flags)
+{
+ 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;
+ memcpy(&nlmsg->nl, nl, sizeof(struct nlmsghdr));
+ memcpy(nlmsg->data, payload, payload_size);
+
+ 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;
+ 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;
+
+ if (sk == NULL) {
+ return -1;
+ }
+
+ 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;
+}
+
+int netlink_sendmsg(struct socket *sock, const struct msghdr *message, int flags)
+{
+ struct sock *sk = sock->sk;
+
+ if (sk == NULL) {
+ return -1;
+ }
+
+ 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);
+
+ rc += nl->nlmsg_len;
+ }
+
+ 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->sock->fd == sockfd) {
+ nlm = entry;
+ }
+ }
+ pthread_rwlock_unlock(&mlock);
+
+ 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;
+
+ memset(ptr, 0, sizeof(struct inet_diag_msg));
+
+ idm->idiag_family = AF_INET;
+ idm->idiag_state = s->sk->state;
+ 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;
+ 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);
+}
+
+int process_netlink_request_tcp(struct nlmsghdr *nl, struct nl_message *req)
+{
+
+ struct inet_diag_msg *tmp = NULL;
+
+ 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");
+ return -1;
+ }
+
+ struct
+ {
+ struct nlmsghdr nlh;
+ struct inet_diag_msg idm;
+ struct nlattr nla;
+ uint32_t flag;
+ } resp[rc];
+
+ 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[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));
+
+ if (tmp != NULL) {
+ free(tmp);
+ }
+
+ return size * rc;
+}
+
+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;
+
+ if (req == NULL) {
+ return 0;
+ }
+
+ 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:
+ 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))) {
+ // Request has been consumed, delete it
+ assert(message_free(req) == 0);
+ }
+
+ return rc;
+}
+
+int netlink_recvmsg(struct socket *sock, struct msghdr *message, int flags)
+{
+ struct sock *sk = sock->sk;
+
+ if (sk == NULL) {
+ 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;
+ memset(nl, 0, sizeof(struct nlmsghdr));
+
+ struct nl_message *nlm = find_netlink_request(sock->fd);
+
+ 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;
+}
diff --git a/src/socket.c b/src/socket.c
index 0bac153..d085ef4 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)
@@ -181,6 +184,47 @@ struct socket *socket_find(struct socket *find)
return sock;
}
+int filter_sockets(int family, int type, 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->type == type) {
+ allocated += size;
+
+ *store = realloc(*store, allocated);
+ if (*store == NULL) {
+ perror("Failed on allocating socket filter store memory");
+ goto error;
+ }
+
+ rc = f(sock, (*store + (rc * amount)));
+
+ if (rc < 0) {
+ perror("Failed on socket filtering");
+ goto error;
+ }
+
+ amount++;
+ }
+ }
+
+ return amount;
+
+error:
+ return -1;
+}
+
#ifdef DEBUG_SOCKET
void socket_debug()
{
@@ -216,6 +260,7 @@ int _socket(pid_t pid, int domain, int type, int protocol)
}
sock->type = type;
+ sock->family = domain;
family = families[domain];
@@ -466,3 +511,37 @@ int _getsockname(pid_t pid, int socket, struct sockaddr *restrict address,
return rc;
}
+
+int _sendmsg(pid_t pid, int socket, const struct msghdr *msg, int flags)
+{
+ 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;
+}
+
+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;
+ }
+
+ 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 5677a9d..8aaaf9d 100644
--- a/src/tuntap_if.c
+++ b/src/tuntap_if.c
@@ -6,23 +6,9 @@ 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)
-{
- 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
*/
@@ -34,7 +20,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);
}
@@ -55,8 +41,7 @@ static int tun_alloc(char *dev)
close(fd);
return err;
}
-
- strcpy(dev, ifr.ifr_name);
+
return fd;
}
@@ -72,20 +57,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, tapaddr) != 0) {
- print_err("ERROR when setting addr for if\n");
- }
+ tun_fd = tun_alloc("tap0");
}
void free_tun()
diff --git a/tests/utils/common b/tests/utils/common
index 36b4d3e..a5c51b0 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
@@ -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
}
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 e2512a2..0e8877c 100644
--- a/tools/liblevelip.c
+++ b/tools/liblevelip.c
@@ -8,14 +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;
@@ -23,23 +24,25 @@ 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;
static int lvlip_socks_count = 0;
static LIST_HEAD(lvlip_socks);
@@ -50,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;
};
@@ -59,13 +62,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;
-
- if (!(type & SOCK_STREAM)) return 0;
-
- if (protocol != 0 && protocol != IPPROTO_TCP) return 0;
+ int supported = 0;
+
+ switch (domain) {
+ case AF_INET:
+ if (type & SOCK_STREAM &&
+ (protocol == IPPROTO_TCP || protocol == 0)) 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)
@@ -96,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);
@@ -123,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;
}
@@ -147,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;
@@ -167,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);
@@ -181,7 +194,7 @@ int socket(int domain, int type, int protocol)
sock->fd = sockfd;
lvl_sock_dbg("Socket called", sock);
-
+
return sockfd;
}
@@ -195,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;
@@ -223,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;
@@ -256,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;
@@ -285,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;
@@ -308,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;
}
@@ -332,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;
}
@@ -342,30 +363,211 @@ 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);
}
+ssize_t sendmsg(int socket, const struct msghdr *message, int flags)
+{
+ struct lvlip_sock *sock = lvlip_get_sock(socket);
+
+ if (sock == NULL) return _sendmsg(socket, message, flags);
+
+ lvl_sock_dbg("Sendmsg 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_SENDMSG;
+ 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);
+
+ struct sockaddr_nl *snl = message->msg_name;
+ snl->nl_pid = 0;
+
+ lvl_sock_dbg("Sendmsg returning rc %d", sock, rc);
+
+ return rc;
+}
+
ssize_t recv(int fd, void *buf, size_t len, int flags)
{
return recvfrom(fd, buf, len, flags, NULL, 0);
}
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);
}
+ssize_t recvmsg(int socket, struct msghdr *message, int flags)
+{
+ struct lvlip_sock *sock = lvlip_get_sock(socket);
+
+ if (sock == NULL) return _recvmsg(socket, message, flags);
+
+ 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;
+ 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;
+ }
+
+ // Send mocked syscall to lvl-ip
+ if (_write(sock->lvlfd, (char *)msg, msglen) == -1) {
+ perror("Error on writing IPC recvmsg");
+ }
+
+ 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");
+ }
+
+ 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) {
+ 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;
+ }
+
+ 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");
+ }
+
+ 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++) {
+ 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;
+ }
+
+ 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;
+}
+
int poll(struct pollfd *fds, nfds_t nfds, int timeout)
{
struct pollfd *kernel_fds[nfds];
@@ -402,7 +604,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) {
@@ -415,11 +617,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;
@@ -452,13 +655,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;
}
@@ -478,12 +681,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;
}
}
@@ -493,21 +696,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);
@@ -515,7 +718,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);
@@ -523,23 +726,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;
@@ -566,13 +771,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;
}
@@ -585,7 +790,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;
@@ -599,7 +804,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);
@@ -610,6 +815,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;
@@ -629,13 +836,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;
}
@@ -648,7 +855,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);
@@ -656,12 +863,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);
@@ -672,6 +879,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;
@@ -691,13 +900,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;
}
@@ -710,7 +919,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);
@@ -743,6 +952,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;
@@ -750,37 +960,49 @@ 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;
}
+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))
+ char * * ubp_av, void (*init) (void), void (*fini) (void),
+ void (*rtld_fini) (void), void (* stack_end))
{
__start_main = dlsym(RTLD_NEXT, "__libc_start_main");
@@ -800,6 +1022,9 @@ 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");
+ _sendmsg = dlsym(RTLD_NEXT, "sendmsg");
+ _recvmsg = dlsym(RTLD_NEXT, "recvmsg");
list_init(&lvlip_socks);