| 1 | /* -*-c-*- |
| 2 | * |
| 3 | * Address-type specific functionality |
| 4 | * |
| 5 | * (c) 2012 Straylight/Edgeware |
| 6 | */ |
| 7 | |
| 8 | /*----- Licensing notice --------------------------------------------------* |
| 9 | * |
| 10 | * This file is part of Yet Another Ident Daemon (YAID). |
| 11 | * |
| 12 | * YAID is free software; you can redistribute it and/or modify |
| 13 | * it under the terms of the GNU General Public License as published by |
| 14 | * the Free Software Foundation; either version 2 of the License, or |
| 15 | * (at your option) any later version. |
| 16 | * |
| 17 | * YAID is distributed in the hope that it will be useful, |
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 20 | * GNU General Public License for more details. |
| 21 | * |
| 22 | * You should have received a copy of the GNU General Public License |
| 23 | * along with YAID; if not, write to the Free Software Foundation, |
| 24 | * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| 25 | */ |
| 26 | |
| 27 | /*----- Header files ------------------------------------------------------*/ |
| 28 | |
| 29 | #include "yaid.h" |
| 30 | |
| 31 | /*----- IPv4 addresses ----------------------------------------------------*/ |
| 32 | |
| 33 | static int addreq_ipv4(const union addr *a, const union addr *b) |
| 34 | { return a->ipv4.s_addr == b->ipv4.s_addr; } |
| 35 | |
| 36 | static int match_addrpat_ipv4(const struct addrpat *ap, const union addr *a) |
| 37 | { |
| 38 | unsigned m; |
| 39 | |
| 40 | if (!ap->len) return (1); |
| 41 | m = htonl((MASK32 << (32 - ap->len)) & MASK32); |
| 42 | return (((ap->addr.ipv4.s_addr ^ a->ipv4.s_addr) & m) == 0); |
| 43 | } |
| 44 | |
| 45 | static void socket_to_sockaddr_ipv4(const struct socket *s, |
| 46 | void *sa, size_t *ssz) |
| 47 | { |
| 48 | struct sockaddr_in *sin = sa; |
| 49 | |
| 50 | sin->sin_family = AF_INET; |
| 51 | sin->sin_addr = s->addr.ipv4; |
| 52 | sin->sin_port = htons(s->port); |
| 53 | *ssz = sizeof(*sin); |
| 54 | } |
| 55 | |
| 56 | static void sockaddr_to_addr_ipv4(const void *sa, union addr *a) |
| 57 | { const struct sockaddr_in *sin = sa; a->ipv4 = sin->sin_addr; } |
| 58 | |
| 59 | static int init_listen_socket_ipv4(int fd) { return (0); } |
| 60 | |
| 61 | static const union addr any_ipv4 = { .ipv4.s_addr = INADDR_ANY }; |
| 62 | |
| 63 | /*----- IPv6 addresses ----------------------------------------------------*/ |
| 64 | |
| 65 | static int addreq_ipv6(const union addr *a, const union addr *b) |
| 66 | { return !memcmp(a->ipv6.s6_addr, b->ipv6.s6_addr, 16); } |
| 67 | |
| 68 | static int match_addrpat_ipv6(const struct addrpat *ap, const union addr *a) |
| 69 | { |
| 70 | unsigned i = 0, m, n = ap->len; |
| 71 | |
| 72 | if (!n) return (1); |
| 73 | for (i = 0; n >= 8; i++, n -= 8) |
| 74 | if (ap->addr.ipv6.s6_addr[i] != a->ipv6.s6_addr[i]) return (0); |
| 75 | if (!n) return (1); |
| 76 | m = (MASK8 << (8 - n)) & MASK8; |
| 77 | return (((ap->addr.ipv6.s6_addr[i] ^ a->ipv6.s6_addr[i]) & m) == 0); |
| 78 | } |
| 79 | |
| 80 | static void socket_to_sockaddr_ipv6(const struct socket *s, |
| 81 | void *sa, size_t *ssz) |
| 82 | { |
| 83 | struct sockaddr_in6 *sin6 = sa; |
| 84 | |
| 85 | sin6->sin6_family = AF_INET6; |
| 86 | sin6->sin6_addr = s->addr.ipv6; |
| 87 | sin6->sin6_port = htons(s->port); |
| 88 | sin6->sin6_flowinfo = 0; |
| 89 | sin6->sin6_scope_id = 0; |
| 90 | *ssz = sizeof(*sin6); |
| 91 | } |
| 92 | |
| 93 | static void sockaddr_to_addr_ipv6(const void *sa, union addr *a) |
| 94 | { const struct sockaddr_in6 *sin6 = sa; a->ipv6 = sin6->sin6_addr; } |
| 95 | |
| 96 | static int init_listen_socket_ipv6(int fd) |
| 97 | { |
| 98 | int yes = 1; |
| 99 | |
| 100 | if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes))) |
| 101 | return (-1); |
| 102 | return (0); |
| 103 | } |
| 104 | |
| 105 | static const union addr any_ipv6 = { .ipv6 = IN6ADDR_ANY_INIT }; |
| 106 | |
| 107 | /*----- General utilities -------------------------------------------------*/ |
| 108 | |
| 109 | int sockeq(const struct addrops *ao, |
| 110 | const struct socket *sa, const struct socket *sb) |
| 111 | { return (ao->addreq(&sa->addr, &sb->addr) && sa->port == sb->port); } |
| 112 | |
| 113 | void dputsock(dstr *d, const struct addrops *ao, const struct socket *s) |
| 114 | { |
| 115 | char buf[ADDRLEN]; |
| 116 | |
| 117 | inet_ntop(ao->af, &s->addr, buf, sizeof(buf)); |
| 118 | if (!s->port || ao->af != AF_INET6) dstr_puts(d, buf); |
| 119 | else { dstr_putc(d, '['); dstr_puts(d, buf); dstr_putc(d, ']'); } |
| 120 | if (s->port) dstr_putf(d, ":%d", s->port); |
| 121 | } |
| 122 | |
| 123 | /*----- The operations table ----------------------------------------------*/ |
| 124 | |
| 125 | const struct addrops addroptab[] = { |
| 126 | #define DEFOPS(ty, TY, af, name, len) \ |
| 127 | { AF_##af, name, len, &any_##ty, &addrops_sys_##ty, \ |
| 128 | addreq_##ty, match_addrpat_##ty, \ |
| 129 | socket_to_sockaddr_##ty, sockaddr_to_addr_##ty, \ |
| 130 | init_listen_socket_##ty }, |
| 131 | ADDRTYPES(DEFOPS) |
| 132 | { 0 } |
| 133 | #undef DEFOPS |
| 134 | }; |
| 135 | |
| 136 | /*----- That's all, folks -------------------------------------------------*/ |