| 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 | #define ADDRFAM_IPV4 AF_INET |
| 34 | #define NAME_IPV4 "IPv4" |
| 35 | #define ADDRLEN_IPV4 32 |
| 36 | |
| 37 | static int addreq_ipv4(const union addr *a, const union addr *b) |
| 38 | { return a->ipv4.s_addr == b->ipv4.s_addr; } |
| 39 | |
| 40 | static int match_addrpat_ipv4(const struct addrpat *ap, const union addr *a) |
| 41 | { |
| 42 | unsigned m; |
| 43 | |
| 44 | if (!ap->len) return (1); |
| 45 | m = htonl((MASK32 << (32 - ap->len)) & MASK32); |
| 46 | return (((ap->addr.ipv4.s_addr ^ a->ipv4.s_addr) & m) == 0); |
| 47 | } |
| 48 | |
| 49 | static void socket_to_sockaddr_ipv4(const struct socket *s, |
| 50 | void *sa, size_t *ssz) |
| 51 | { |
| 52 | struct sockaddr_in *sin = sa; |
| 53 | |
| 54 | sin->sin_family = AF_INET; |
| 55 | sin->sin_addr = s->addr.ipv4; |
| 56 | sin->sin_port = htons(s->port); |
| 57 | *ssz = sizeof(*sin); |
| 58 | } |
| 59 | |
| 60 | static void sockaddr_to_addr_ipv4(const void *sa, union addr *a) |
| 61 | { const struct sockaddr_in *sin = sa; a->ipv4 = sin->sin_addr; } |
| 62 | |
| 63 | static int init_listen_socket_ipv4(int fd) { return (0); } |
| 64 | |
| 65 | static const union addr any_ipv4 = { .ipv4.s_addr = INADDR_ANY }; |
| 66 | |
| 67 | /*----- IPv6 addresses ----------------------------------------------------*/ |
| 68 | |
| 69 | #define ADDRFAM_IPV6 AF_INET6 |
| 70 | #define NAME_IPV6 "IPv6" |
| 71 | #define ADDRLEN_IPV6 128 |
| 72 | |
| 73 | static int addreq_ipv6(const union addr *a, const union addr *b) |
| 74 | { return !memcmp(a->ipv6.s6_addr, b->ipv6.s6_addr, 16); } |
| 75 | |
| 76 | static int match_addrpat_ipv6(const struct addrpat *ap, const union addr *a) |
| 77 | { |
| 78 | unsigned i = 0, m, n = ap->len; |
| 79 | |
| 80 | if (!n) return (1); |
| 81 | for (i = 0; n >= 8; i++, n -= 8) |
| 82 | if (ap->addr.ipv6.s6_addr[i] != a->ipv6.s6_addr[i]) return (0); |
| 83 | if (!n) return (1); |
| 84 | m = (MASK8 << (8 - n)) & MASK8; |
| 85 | return (((ap->addr.ipv6.s6_addr[i] ^ a->ipv6.s6_addr[i]) & m) == 0); |
| 86 | } |
| 87 | |
| 88 | static void socket_to_sockaddr_ipv6(const struct socket *s, |
| 89 | void *sa, size_t *ssz) |
| 90 | { |
| 91 | struct sockaddr_in6 *sin6 = sa; |
| 92 | |
| 93 | sin6->sin6_family = AF_INET6; |
| 94 | sin6->sin6_addr = s->addr.ipv6; |
| 95 | sin6->sin6_port = htons(s->port); |
| 96 | sin6->sin6_flowinfo = 0; |
| 97 | sin6->sin6_scope_id = 0; |
| 98 | *ssz = sizeof(*sin6); |
| 99 | } |
| 100 | |
| 101 | static void sockaddr_to_addr_ipv6(const void *sa, union addr *a) |
| 102 | { const struct sockaddr_in6 *sin6 = sa; a->ipv6 = sin6->sin6_addr; } |
| 103 | |
| 104 | static int init_listen_socket_ipv6(int fd) |
| 105 | { |
| 106 | int yes = 1; |
| 107 | |
| 108 | if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes))) |
| 109 | return (-1); |
| 110 | return (0); |
| 111 | } |
| 112 | |
| 113 | static const union addr any_ipv6 = { .ipv6 = IN6ADDR_ANY_INIT }; |
| 114 | |
| 115 | /*----- General utilities -------------------------------------------------*/ |
| 116 | |
| 117 | /* Answer whether the sockets SA and SB are equal. */ |
| 118 | int sockeq(const struct addrops *ao, |
| 119 | const struct socket *sa, const struct socket *sb) |
| 120 | { return (ao->addreq(&sa->addr, &sb->addr) && sa->port == sb->port); } |
| 121 | |
| 122 | /* Write a textual description of S to the string D. */ |
| 123 | void dputsock(dstr *d, const struct addrops *ao, const struct socket *s) |
| 124 | { |
| 125 | char buf[ADDRLEN]; |
| 126 | |
| 127 | inet_ntop(ao->af, &s->addr, buf, sizeof(buf)); |
| 128 | if (!s->port || ao->af != AF_INET6) dstr_puts(d, buf); |
| 129 | else { dstr_putc(d, '['); dstr_puts(d, buf); dstr_putc(d, ']'); } |
| 130 | if (s->port) dstr_putf(d, ":%d", s->port); |
| 131 | } |
| 132 | |
| 133 | /*----- The operations table ----------------------------------------------*/ |
| 134 | |
| 135 | const struct addrops addroptab[] = { |
| 136 | #define DEFOPS(ty, TY) \ |
| 137 | { ADDRFAM_##TY, NAME_##TY, ADDRLEN_##TY, \ |
| 138 | &any_##ty, &addrops_sys_##ty, \ |
| 139 | addreq_##ty, match_addrpat_##ty, \ |
| 140 | socket_to_sockaddr_##ty, sockaddr_to_addr_##ty, \ |
| 141 | init_listen_socket_##ty }, |
| 142 | ADDRTYPES(DEFOPS) |
| 143 | { 0 } |
| 144 | #undef DEFOPS |
| 145 | }; |
| 146 | |
| 147 | /*----- That's all, folks -------------------------------------------------*/ |