diff options
Diffstat (limited to 'libmailutils/cidr')
-rw-r--r-- | libmailutils/cidr/Makefile.am | 27 | ||||
-rw-r--r-- | libmailutils/cidr/fromsa.c | 101 | ||||
-rw-r--r-- | libmailutils/cidr/fromstr.c | 128 | ||||
-rw-r--r-- | libmailutils/cidr/match.c | 38 | ||||
-rw-r--r-- | libmailutils/cidr/tosa.c | 78 | ||||
-rw-r--r-- | libmailutils/cidr/tostr.c | 159 |
6 files changed, 531 insertions, 0 deletions
diff --git a/libmailutils/cidr/Makefile.am b/libmailutils/cidr/Makefile.am new file mode 100644 index 000000000..408806f79 --- /dev/null +++ b/libmailutils/cidr/Makefile.am @@ -0,0 +1,27 @@ +# GNU Mailutils -- a suite of utilities for electronic mail +# Copyright (C) 2011 Free Software Foundation, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 3 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General +# Public License along with this library. If not, see +# <http://www.gnu.org/licenses/>. + +noinst_LTLIBRARIES = libcidr.la + +libcidr_la_SOURCES = \ + fromsa.c\ + fromstr.c\ + match.c\ + tosa.c\ + tostr.c + +INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils diff --git a/libmailutils/cidr/fromsa.c b/libmailutils/cidr/fromsa.c new file mode 100644 index 000000000..a2fda6680 --- /dev/null +++ b/libmailutils/cidr/fromsa.c @@ -0,0 +1,101 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2011 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <string.h> +#include <stdlib.h> +#include <mailutils/cidr.h> +#include <mailutils/errno.h> + +static void +uint32_to_bytes (unsigned char *bytes, uint32_t u) +{ + int i; + + for (i = 0; i < 4; i++) + { + bytes[i] = u & 0xff; + u >>= 8; + } +} + +int +_mu_inaddr_to_bytes (int af, void *buf, unsigned char *bytes) +{ + uint32_t u; + + switch (af) + { + case AF_INET: + memcpy (&u, buf, sizeof u); + uint32_to_bytes (bytes, u); + return 4; + +#ifdef MAILUTILS_IPV6 + case AF_INET6: + memcpy (bytes, buf, 16); + return 16; +#endif + } + return 0; +} + +int +_mu_sockaddr_to_bytes (unsigned char *bytes, struct sockaddr const *sa) +{ + switch (sa->sa_family) + { + case AF_INET: + uint32_to_bytes (bytes, ((struct sockaddr_in*)sa)->sin_addr.s_addr); + return 4; + +#ifdef MAILUTILS_IPV6 + case AF_INET6: + memcpy (bytes, &((struct sockaddr_in6*)sa)->sin6_addr, 16); + return 16; +#endif + } + return 0; +} + +int +mu_cidr_from_sockaddr (struct mu_cidr *cidr, const struct sockaddr *sa) +{ + unsigned char address[MU_INADDR_BYTES]; + int len; + int i; + + len = _mu_sockaddr_to_bytes (address, sa); + if (len == 0) + return MU_ERR_FAMILY; + cidr->family = sa->sa_family; + cidr->len = len; + memcpy (cidr->address, address, sizeof (cidr->address)); + for (i = 0; i < MU_INADDR_BYTES; i++) + cidr->netmask[i] = 0xff; + return 0; +} + + diff --git a/libmailutils/cidr/fromstr.c b/libmailutils/cidr/fromstr.c new file mode 100644 index 000000000..4e7a56f80 --- /dev/null +++ b/libmailutils/cidr/fromstr.c @@ -0,0 +1,128 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2011 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <string.h> +#include <stdlib.h> +#include <arpa/inet.h> +#include <mailutils/cidr.h> +#include <mailutils/errno.h> +#include <mailutils/sockaddr.h> + +static void +masklen_to_netmask (unsigned char *buf, size_t len, size_t masklen) +{ + int i, cnt; + + cnt = masklen / 8; + for (i = 0; i < cnt; i++) + buf[i] = 0xff; + if (i == MU_INADDR_BYTES) + return; + cnt = 8 - masklen % 8; + buf[i++] = (0xff >> cnt) << cnt; + for (; i < MU_INADDR_BYTES; i++) + buf[i] = 0; +} + +int +mu_cidr_from_string (struct mu_cidr *pcidr, const char *str) +{ + int rc; + char ipbuf[41]; + struct mu_cidr cidr; + char *p; + size_t len; + union + { + struct in_addr in; +#ifdef MAILUTILS_IPV6 + struct in6_addr in6; +#endif + } inaddr; + + p = strchr (str, '/'); + if (p) + len = p - str; + else + len = strlen (str); + + if (len > sizeof (ipbuf)) + return MU_ERR_BUFSPACE; + + memcpy (ipbuf, str, len); + ipbuf[len] = 0; + + if (mu_str_is_ipv4 (ipbuf)) + cidr.family = AF_INET; +#ifdef MAILUTILS_IPV6 + else if (mu_str_is_ipv6 (ipbuf)) + cidr.family = AF_INET6; +#endif + else + return MU_ERR_FAMILY; + + rc = inet_pton (cidr.family, ipbuf, &inaddr); + if (rc == -1) + return MU_ERR_FAMILY; + else if (rc == 0) + return MU_ERR_NONAME; + else if (rc != 1) + return MU_ERR_FAILURE; + + cidr.len = _mu_inaddr_to_bytes (cidr.family, &inaddr, cidr.address); + if (cidr.len == 0) + return MU_ERR_FAMILY; + + if (p) + { + char *end; + unsigned long masklen; + + p++; + + masklen = strtoul (p, &end, 10); + if (*end == 0) + masklen_to_netmask (cidr.netmask, cidr.len, masklen); + else if ((cidr.family == AF_INET && mu_str_is_ipv4 (p)) +#ifdef MAILUTILS_IPV6 + || (cidr.family == AF_INET6 && mu_str_is_ipv6 (ipbuf)) +#endif + ) + { + rc = inet_pton (cidr.family, p, &inaddr); + if (rc == -1) + return MU_ERR_FAMILY; + else if (rc == 0) + return MU_ERR_NONAME; + else if (rc != 1) + return MU_ERR_FAILURE; + + _mu_inaddr_to_bytes (cidr.family, &inaddr, cidr.netmask); + } + else + return MU_ERR_FAMILY; + } + else + masklen_to_netmask (cidr.netmask, cidr.len, cidr.len * 8); + + memcpy (pcidr, &cidr, sizeof (*pcidr)); + return 0; +} + diff --git a/libmailutils/cidr/match.c b/libmailutils/cidr/match.c new file mode 100644 index 000000000..dff9194ee --- /dev/null +++ b/libmailutils/cidr/match.c @@ -0,0 +1,38 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2011 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <mailutils/cidr.h> +#include <mailutils/errno.h> + +int +mu_cidr_match (struct mu_cidr *a, struct mu_cidr *b) +{ + int i; + + if (a->family != b->family) + return 1; + for (i = 0; i < a->len; i++) + { + if (a->address[i] != (b->address[i] & a->netmask[i])) + return 1; + } + return 0; +} + diff --git a/libmailutils/cidr/tosa.c b/libmailutils/cidr/tosa.c new file mode 100644 index 000000000..c14a995da --- /dev/null +++ b/libmailutils/cidr/tosa.c @@ -0,0 +1,78 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2011 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <string.h> +#include <stdlib.h> +#include <mailutils/cidr.h> +#include <mailutils/errno.h> + +int +mu_cidr_to_sockaddr (struct mu_cidr *cidr, struct sockaddr **psa) +{ + union + { + struct sockaddr sa; + struct sockaddr_in s_in; +#ifdef MAILUTILS_IPV6 + struct sockaddr_in6 s_in6; +#endif + } addr; + struct sockaddr *sa; + int socklen; + int i; + + memset (&addr, 0, sizeof (addr)); + addr.sa.sa_family = cidr->family; + switch (cidr->family) + { + case AF_INET: + socklen = sizeof (addr.s_in); + for (i = 0; i < cidr->len; i++) + { + addr.s_in.sin_addr.s_addr <<= 8; + addr.s_in.sin_addr.s_addr |= cidr->address[i]; + } + break; + +#ifdef MAILUTILS_IPV6 + case AF_INET6: + socklen = sizeof (addr.s_in6); + memcpy (&addr.s_in6.sin6_addr, cidr->address, 16); + break; +#endif + + default: + return MU_ERR_FAMILY; + } + + sa = malloc (socklen); + if (!sa) + return ENOMEM; + memcpy (sa, &addr, socklen); + *psa = sa; + return 0; +} + diff --git a/libmailutils/cidr/tostr.c b/libmailutils/cidr/tostr.c new file mode 100644 index 000000000..3d1ee5f49 --- /dev/null +++ b/libmailutils/cidr/tostr.c @@ -0,0 +1,159 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2011 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <string.h> +#include <stdlib.h> +#include <mailutils/cidr.h> +#include <mailutils/errno.h> + +static int +to_xdig (unsigned char b) +{ + if (b >= 0xa) + return 'A' + b - 0xa; + else + return '0' + b; +} + +static size_t +format_ipv6_bytes (const unsigned char *bytes, int len, + char *buf, size_t size) +{ + size_t total = 0; + int i; + + for (i = 0; i < len; i += 2) + { + if (i) + { + if (total++ < size) + *buf++ = ':'; + } + if (total++ < size) + *buf++ = to_xdig (*bytes >> 4); + if (total++ < size) + *buf++ = to_xdig (*bytes & 0xf); + bytes++; + if (total++ < size) + *buf++ = to_xdig (*bytes >> 4); + if (total++ < size) + *buf++ = to_xdig (*bytes & 0xf); + bytes++; + } + return total; +} + +static size_t +format_ipv4_bytes (const unsigned char *bytes, int len, + char *buf, size_t size) +{ + int i; + size_t total = 0; + + for (i = 0; i < len; i++) + { + unsigned char b = *bytes++; + char nbuf[3]; + int j; + + if (i) + { + if (total++ < size) + *buf++ = '.'; + } + + j = 0; + do + { + nbuf[j++] = b % 10 + '0'; + b /= 10; + } + while (b); + + for (; j; j--) + { + if (total++ < size) + *buf++ = nbuf[j - 1]; + } + } + return total; +} + +int +mu_cidr_to_string (struct mu_cidr *cidr, int flags, + char *buf, size_t size, size_t *pret) +{ + size_t (*fmt) (const unsigned char *bytes, int len, char *buf, size_t size); + size_t n, total = 0; + + if (size == 0) + return MU_ERR_BUFSPACE; + size--; + switch (cidr->family) + { + case AF_INET: + fmt = format_ipv4_bytes; + break; + +#ifdef MAILUTILS_IPV6 + case AF_INET6: + fmt = format_ipv6_bytes; + break; +#endif + + default: + return MU_ERR_FAMILY; + } + + n = fmt (cidr->address, cidr->len, buf, size); + if (buf) + buf += n; + total += n; + + if (!(flags & MU_CIDR_FMT_ADDRONLY)) + { + if (total++ < size) + *buf++ = '/'; + n = fmt (cidr->netmask, cidr->len, buf, size - total); + if (buf) + buf += n; + total += n; + } + + if (buf) + *buf++ = 0; + if (pret) + *pret = total; + return 0; +} + +int +mu_cidr_format (struct mu_cidr *cidr, int flags, char **pbuf) +{ + char buf[MU_CIDR_MAXBUFSIZE]; + int rc = mu_cidr_to_string (cidr, flags, buf, sizeof (buf), NULL); + if (rc) + return rc; + *pbuf = strdup (buf); + if (!*buf) + return ENOMEM; + return 0; +} + |