summaryrefslogtreecommitdiffstats
path: root/sysdep/unix/io.c
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2008-10-27 00:20:22 +0100
committerOndrej Zajicek <santiago@crfreenet.org>2008-10-27 00:20:22 +0100
commita98fbf0f12b5e83e25afa0f585ca6a4d4ac5f6bf (patch)
treef6c215cd05ec9278696fae7b8814b5071a4b3c6a /sysdep/unix/io.c
parenta3b70dc499b64f41aa776b5b4afee5c7bfb8dfa6 (diff)
parent1567edea8d3da7da08092eef15bb3bd4544c6464 (diff)
downloadbird-a98fbf0f12b5e83e25afa0f585ca6a4d4ac5f6bf.tar
bird-a98fbf0f12b5e83e25afa0f585ca6a4d4ac5f6bf.zip
Merge branch 'dev' into out
Diffstat (limited to 'sysdep/unix/io.c')
-rw-r--r--sysdep/unix/io.c75
1 files changed, 75 insertions, 0 deletions
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;