summaryrefslogtreecommitdiffstats
path: root/sysdep
diff options
context:
space:
mode:
Diffstat (limited to 'sysdep')
-rw-r--r--sysdep/linux/netlink/netlink.c9
-rw-r--r--sysdep/linux/sysio.h21
-rw-r--r--sysdep/unix/io.c75
-rw-r--r--sysdep/unix/krt-set.c2
-rw-r--r--sysdep/unix/krt.c2
5 files changed, 103 insertions, 6 deletions
diff --git a/sysdep/linux/netlink/netlink.c b/sysdep/linux/netlink/netlink.c
index 4784195..38d00af 100644
--- a/sysdep/linux/netlink/netlink.c
+++ b/sysdep/linux/netlink/netlink.c
@@ -499,6 +499,8 @@ nl_send_route(struct krt_proto *p, rte *e, int new)
nl_add_attr_ipa(&r.h, sizeof(r), RTA_GATEWAY, a->gw);
break;
case RTD_DEVICE:
+ if (!a->iface)
+ return;
r.r.rtm_type = RTN_UNICAST;
nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, a->iface->index);
break;
@@ -532,11 +534,8 @@ krt_set_notify(struct krt_proto *p, net *n UNUSED, rte *new, rte *old)
else
{
if (old)
- {
- if (!old->attrs->iface || (old->attrs->iface->flags & IF_UP))
- nl_send_route(p, old, 0);
- /* else the kernel has already flushed it */
- }
+ nl_send_route(p, old, 0);
+
if (new)
nl_send_route(p, new, 1);
}
diff --git a/sysdep/linux/sysio.h b/sysdep/linux/sysio.h
index 3a29cdc..b0aff71 100644
--- a/sysdep/linux/sysio.h
+++ b/sysdep/linux/sysio.h
@@ -139,3 +139,24 @@ static inline char *sysio_mcast_join(sock *s)
#endif
#endif
+
+#include <linux/socket.h>
+#include <linux/tcp.h>
+
+/* For the case that we have older kernel headers */
+/* Copied from Linux kernel file include/linux/tcp.h */
+
+#ifndef TCP_MD5SIG
+
+#define TCP_MD5SIG 14
+#define TCP_MD5SIG_MAXKEYLEN 80
+
+struct tcp_md5sig {
+ struct __kernel_sockaddr_storage tcpm_addr; /* address associated */
+ __u16 __tcpm_pad1; /* zero */
+ __u16 tcpm_keylen; /* key length */
+ __u32 __tcpm_pad2; /* zero */
+ __u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* key (binary) */
+};
+
+#endif
diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c
index fa471f6..8cec2cd 100644
--- a/sysdep/unix/io.c
+++ b/sysdep/unix/io.c
@@ -546,6 +546,7 @@ sk_new(pool *p)
s->err_hook = NULL;
s->fd = -1;
s->rbuf_alloc = s->tbuf_alloc = NULL;
+ s->password = NULL;
return s;
}
@@ -642,6 +643,71 @@ bad:
return err;
}
+
+/* FIXME: check portability */
+
+static int
+sk_set_md5_auth_int(sock *s, sockaddr *sa, char *passwd)
+{
+ struct tcp_md5sig md5;
+
+ memset(&md5, 0, sizeof(md5));
+ memcpy(&md5.tcpm_addr, (struct sockaddr *) sa, sizeof(*sa));
+
+ if (passwd)
+ {
+ int len = strlen(passwd);
+
+ if (len > TCP_MD5SIG_MAXKEYLEN)
+ {
+ log(L_ERR "MD5 password too long");
+ return -1;
+ }
+
+ md5.tcpm_keylen = len;
+ memcpy(&md5.tcpm_key, passwd, len);
+ }
+
+ int rv = setsockopt(s->fd, IPPROTO_TCP, TCP_MD5SIG, &md5, sizeof(md5));
+
+ if (rv < 0)
+ {
+ if (errno == ENOPROTOOPT)
+ log(L_ERR "Kernel does not support TCP MD5 signatures");
+ else
+ log(L_ERR "sk_set_md5_auth_int: setsockopt: %m");
+ }
+
+ return rv;
+}
+
+/**
+ * sk_set_md5_auth - add / remove MD5 security association for given socket.
+ * @s: socket
+ * @a: IP address of the other side
+ * @passwd: password used for MD5 authentication
+ *
+ * In TCP MD5 handling code in kernel, there is a set of pairs
+ * (address, password) used to choose password according to
+ * address of the other side. This function is useful for
+ * listening socket, for active sockets it is enough to set
+ * s->password field.
+ *
+ * When called with passwd != NULL, the new pair is added,
+ * When called with passwd == NULL, the existing pair is removed.
+ *
+ * Result: 0 for success, -1 for an error.
+ */
+
+int
+sk_set_md5_auth(sock *s, ip_addr a, char *passwd)
+{
+ sockaddr sa;
+ fill_in_sockaddr(&sa, a, 0);
+ return sk_set_md5_auth_int(s, &sa, passwd);
+}
+
+
static void
sk_tcp_connected(sock *s)
{
@@ -805,6 +871,14 @@ sk_open(sock *s)
ERR("bind");
}
fill_in_sockaddr(&sa, s->daddr, s->dport);
+
+ if (s->password)
+ {
+ int rv = sk_set_md5_auth_int(s, &sa, s->password);
+ if (rv < 0)
+ goto bad_no_log;
+ }
+
switch (type)
{
case SK_TCP_ACTIVE:
@@ -846,6 +920,7 @@ sk_open(sock *s)
bad:
log(L_ERR "sk_open: %s: %m", err);
+bad_no_log:
close(fd);
s->fd = -1;
return -1;
diff --git a/sysdep/unix/krt-set.c b/sysdep/unix/krt-set.c
index bd56448..23cbe5c 100644
--- a/sysdep/unix/krt-set.c
+++ b/sysdep/unix/krt-set.c
@@ -61,6 +61,8 @@ krt_ioctl(int ioc, rte *e, char *name)
re.rt_flags |= RTF_GATEWAY;
break;
case RTD_DEVICE:
+ if (!a->iface)
+ return;
re.rt_dev = a->iface->name;
break;
#ifdef RTF_REJECT
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index a6d1727..5269eb7 100644
--- a/sysdep/unix/krt.c
+++ b/sysdep/unix/krt.c
@@ -684,7 +684,7 @@ krt_notify(struct proto *P, net *net, rte *new, rte *old, struct ea_list *attrs
{
struct krt_proto *p = (struct krt_proto *) P;
- if (shutting_down && KRT_CF->persist)
+ if (shutting_down)
return;
if (new && (!krt_capable(new) || new->attrs->source == RTS_INHERIT))
new = NULL;