--- /dev/null
+/* -*-c-*-
+ *
+ * Address-type specific functionality
+ *
+ * (c) 2012 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Yet Another Ident Daemon (YAID).
+ *
+ * YAID is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * YAID is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with YAID; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "yaid.h"
+
+/*----- IPv4 addresses ----------------------------------------------------*/
+
+static int addreq_ipv4(const union addr *a, const union addr *b)
+ { return a->ipv4.s_addr == b->ipv4.s_addr; }
+
+static int match_addrpat_ipv4(const struct addrpat *ap, const union addr *a)
+{
+ unsigned m;
+
+ if (!ap->len) return (1);
+ m = htonl((MASK32 << (32 - ap->len)) & MASK32);
+ return (((ap->addr.ipv4.s_addr ^ a->ipv4.s_addr) & m) == 0);
+}
+
+static void socket_to_sockaddr_ipv4(const struct socket *s,
+ void *sa, size_t *ssz)
+{
+ struct sockaddr_in *sin = sa;
+
+ sin->sin_family = AF_INET;
+ sin->sin_addr = s->addr.ipv4;
+ sin->sin_port = htons(s->port);
+ *ssz = sizeof(*sin);
+}
+
+static void sockaddr_to_addr_ipv4(const void *sa, union addr *a)
+ { const struct sockaddr_in *sin = sa; a->ipv4 = sin->sin_addr; }
+
+static int init_listen_socket_ipv4(int fd) { return (0); }
+
+static const union addr any_ipv4 = { .ipv4.s_addr = INADDR_ANY };
+
+/*----- IPv6 addresses ----------------------------------------------------*/
+
+static int addreq_ipv6(const union addr *a, const union addr *b)
+ { return !memcmp(a->ipv6.s6_addr, b->ipv6.s6_addr, 16); }
+
+static int match_addrpat_ipv6(const struct addrpat *ap, const union addr *a)
+{
+ unsigned i = 0, m, n = ap->len;
+
+ if (!n) return (1);
+ for (i = 0; n >= 8; i++, n -= 8)
+ if (ap->addr.ipv6.s6_addr[i] != a->ipv6.s6_addr[i]) return (0);
+ if (!n) return (1);
+ m = (MASK8 << (8 - n)) & MASK8;
+ return (((ap->addr.ipv6.s6_addr[i] ^ a->ipv6.s6_addr[i]) & m) == 0);
+}
+
+static void socket_to_sockaddr_ipv6(const struct socket *s,
+ void *sa, size_t *ssz)
+{
+ struct sockaddr_in6 *sin6 = sa;
+
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_addr = s->addr.ipv6;
+ sin6->sin6_port = htons(s->port);
+ sin6->sin6_flowinfo = 0;
+ sin6->sin6_scope_id = 0;
+ *ssz = sizeof(*sin6);
+}
+
+static void sockaddr_to_addr_ipv6(const void *sa, union addr *a)
+ { const struct sockaddr_in6 *sin6 = sa; a->ipv6 = sin6->sin6_addr; }
+
+static int init_listen_socket_ipv6(int fd)
+{
+ int yes = 1;
+
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)))
+ return (-1);
+ return (0);
+}
+
+static const union addr any_ipv6 = { .ipv6 = IN6ADDR_ANY_INIT };
+
+/*----- General utilities -------------------------------------------------*/
+
+int sockeq(const struct addrops *ao,
+ const struct socket *sa, const struct socket *sb)
+ { return (ao->addreq(&sa->addr, &sb->addr) && sa->port == sb->port); }
+
+void dputsock(dstr *d, const struct addrops *ao, const struct socket *s)
+{
+ char buf[ADDRLEN];
+
+ inet_ntop(ao->af, &s->addr, buf, sizeof(buf));
+ if (!s->port || ao->af != AF_INET6) dstr_puts(d, buf);
+ else { dstr_putc(d, '['); dstr_puts(d, buf); dstr_putc(d, ']'); }
+ if (s->port) dstr_putf(d, ":%d", s->port);
+}
+
+/*----- The operations table ----------------------------------------------*/
+
+const struct addrops addroptab[] = {
+#define DEFOPS(ty, TY, af, name, len) \
+ { AF_##af, name, len, &any_##ty, &addrops_sys_##ty, \
+ addreq_##ty, match_addrpat_##ty, \
+ socket_to_sockaddr_##ty, sockaddr_to_addr_##ty, \
+ init_listen_socket_##ty },
+ADDRTYPES(DEFOPS)
+ { 0 }
+#undef DEFOPS
+};
+
+/*----- That's all, folks -------------------------------------------------*/