aboutsummaryrefslogtreecommitdiff
path: root/src/vmod_remoteip.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vmod_remoteip.c')
-rw-r--r--src/vmod_remoteip.c313
1 files changed, 21 insertions, 292 deletions
diff --git a/src/vmod_remoteip.c b/src/vmod_remoteip.c
index 528b0a4..8bba147 100644
--- a/src/vmod_remoteip.c
+++ b/src/vmod_remoteip.c
@@ -26,314 +26,43 @@
#include <cache/cache.h>
#include <vcl.h>
#include <vcc_if.h>
-#include <vqueue.h>
-#ifdef VPFX
-# define VEVENT(a) VPFX(a)
-#else
-/* For compatibility with varnish prior to 6.2 */
-# define VEVENT(a) a
-#endif
-
-/* Max. number of bytes in an IPv6 address */
-#define MU_INADDR_BYTES 16
-
-/* CIDR representation */
-struct cidr {
- int family; /* Address family */
- int len; /* Number of bytes in the address */
- unsigned char address[MU_INADDR_BYTES];
- unsigned char netmask[MU_INADDR_BYTES];
- VSLIST_ENTRY(cidr) next;
-};
-
-typedef VSLIST_HEAD(,cidr) CIDRHEAD;
-
-/* Returns 1 if ADDR is a valid string representation of IPv4 address */
-static int
-str_is_ipv4(const char *addr, size_t len)
-{
- int dot_count = 0;
- int digit_count = 0;
-
- for (; len; addr++, len--) {
- if (!isascii(*addr))
- return 0;
- if (*addr == '.') {
- if (++dot_count > 3)
- break;
- digit_count = 0;
- }
- else if (!(isdigit(*addr) && ++digit_count <= 3))
- return 0;
- }
- return (dot_count == 3);
-}
-
-#define PFXSTR_IPV4_MAPPED "::ffff:"
-#define PFXLEN_IPV4_MAPPED (sizeof PFXSTR_IPV4_MAPPED - 1)
-
-static int
-str_is_ipv4mapped(const char *addr, size_t len)
-{
- return len > PFXLEN_IPV4_MAPPED
- && strncasecmp(PFXSTR_IPV4_MAPPED, addr, PFXLEN_IPV4_MAPPED)
- == 0
- && str_is_ipv4(addr + PFXLEN_IPV4_MAPPED, len - PFXLEN_IPV4_MAPPED);
-}
-
-/* Returns 1 if ADDR is a valid IPv6 address */
-static int
-str_is_ipv6(const char *addr, size_t len)
-{
- int col_count = 0; /* Number of colons */
- int dcol = 0; /* Did we encounter a double-colon? */
- int dig_count = 0; /* Number of digits in the last group */
-
- for (; len; addr++, len--) {
- if (!isascii (*addr))
- return 0;
- else if (isxdigit(*addr)) {
- if (++dig_count > 4)
- return 0;
- } else if (*addr == ':') {
- if (col_count && dig_count == 0 && ++dcol > 1)
- return 0;
- if (++col_count > 7)
- return 0;
- dig_count = 0;
- }
- else
- return 0;
- }
- return (col_count == 7 || dcol);
-}
-
-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;
- }
-}
+#include <vsa.h>
static int
-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;
-
- case AF_INET6:
- memcpy(bytes, buf, 16);
- return 16;
- }
-
- abort();
-}
-
-/* Fill in the BUF (LEN bytes long) with a network mask corresponding to
- the mask length MASKLEN */
-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 == len)
- return;
- cnt = 8 - masklen % 8;
- buf[i++] = (0xff >> cnt) << cnt;
- for (; i < len; i++)
- buf[i] = 0;
-}
-
-#define CIDR_MAXBUFSIZE 81
-
-/* Convert string STR to CIDR. Return 0 on success and -1 on failure. */
-static int
-str_to_cidr(char const *str, struct cidr *cidr, char **endp)
+is_trusted_ip(VRT_CTX, VCL_ACL acl, char const *ipstr)
{
+ struct addrinfo hints;
+ struct addrinfo *res;
+ struct suckaddr *ip;
int rc;
- char *ipbuf, *ipstart;
- union {
- struct in_addr in;
- struct in6_addr in6;
- } inaddr;
- size_t len;
-
- len = strspn(str, "0123456789abcdefABCDEF.:");
- ipbuf = malloc(len + 1);
- AN(ipbuf);
- memcpy(ipbuf, str, len);
- ipbuf[len] = 0;
- str += len;
-
- ipstart = ipbuf;
-
- if (str_is_ipv4(ipstart, len))
- cidr->family = AF_INET;
- else if (str_is_ipv4mapped(ipstart, len)) {
- cidr->family = AF_INET;
- ipstart += PFXLEN_IPV4_MAPPED;
- } else if (str_is_ipv6(ipbuf, len))
- cidr->family = AF_INET6;
- else {
- free(ipbuf);
- syslog(LOG_DAEMON|LOG_ERR, "invalid CIDR: %s", ipstart);
- return -1;
- }
- rc = inet_pton(cidr->family, ipstart, &inaddr);
- free(ipbuf);
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_NUMERICHOST|AI_NUMERICSERV;
- if (rc != 1) {
- if (rc == -1) {
- syslog(LOG_DAEMON|LOG_ERR, "invalid address family");
- return -1;
- }
- if (rc == 0) {
- syslog(LOG_DAEMON|LOG_ERR,
- "invalid IPv%s address: %s",
- cidr->family == AF_INET ? "4" : "6",
- str - len);
- return -1;
- }
- }
+ rc = getaddrinfo(ipstr, NULL, &hints, &res);
+ if (rc)
+ return 0;
- cidr->len = inaddr_to_bytes(cidr->family, &inaddr, cidr->address);
+ ip = VSA_Malloc(res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
- if (*str == '/') {
- char *end;
- unsigned long masklen;
-
- str++;
+ rc = VRT_acl_match(ctx, acl, ip);
- masklen = strtoul(str, &end, 10);
- if (*end == 0) {
- masklen_to_netmask(cidr->netmask, cidr->len, masklen);
- str = end;
- } else {
- size_t k = strspn(str, "0123456789abcdefABCDEF.:");
-
- if ((cidr->family == AF_INET
- && str_is_ipv4(str, k))
- || (cidr->family == AF_INET6
- && str_is_ipv6(str, k))) {
- char mbuf[CIDR_MAXBUFSIZE];
- memcpy(mbuf, str, k);
- mbuf[k] = 0;
- rc = inet_pton(cidr->family, mbuf, &inaddr);
- if (rc != 1) {
- syslog(LOG_DAEMON|LOG_ERR,
- "bad netmask: %s", mbuf);
- return -1;
- }
- inaddr_to_bytes(cidr->family, &inaddr,
- cidr->netmask);
- } else {
- syslog(LOG_DAEMON|LOG_ERR,
- "bad CIDR (near %s)", str);
- return -1;
- }
- }
- } else
- masklen_to_netmask(cidr->netmask, cidr->len, cidr->len * 8);
- *endp = (char*) str;
- return 0;
-}
-
-/* A is a valid CIDR, and B is a valid IP address represented as CIDR.
- Return 0 if B falls within A */
-static int
-cidr_match(struct cidr *a, struct 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;
-}
-
-static int
-is_trusted_ip(CIDRHEAD *cl, char const *ipstr)
-{
- struct cidr cidr, *cp;
- char *endp;
-
- VSLIST_FOREACH(cp, cl, next) {
- if (str_to_cidr(ipstr, &cidr, &endp) || *endp)
- return 0;
- if (cidr_match(cp, &cidr) == 0)
- return 1;
- }
- return 0;
+ free(ip);
+
+ return rc;
}
-int
-VEVENT(remoteip_event)(VRT_CTX, struct vmod_priv *priv, enum vcl_event_e e)
-{
- CIDRHEAD *p;
-
- switch (e) {
- case VCL_EVENT_LOAD:
- p = calloc(1, sizeof(*p));
- AN(p);
- priv->priv = p;
- break;
- default:
- break;
- }
- return 0;
-}
-
-void
-vmod_init(VRT_CTX, struct vmod_priv *priv, VCL_STRING s)
-{
- CIDRHEAD *cl = priv->priv;
- struct cidr *cidr;
- char *endp;
-
- while (*s) {
- cidr = calloc(1, sizeof(cidr[0]));
- if (str_to_cidr(s, cidr, &endp)) {
- free(cidr);
- break;
- }
- VSLIST_INSERT_HEAD(cl, cidr, next);
- while (*endp && isspace(*endp))
- ++endp;
- if (*endp == 0)
- break;
- AN(*endp == ',');
- ++endp;
- while (*endp && isspace(*endp))
- ++endp;
- s = endp;
- }
-}
-
VCL_STRING
-vmod_get(VRT_CTX, struct vmod_priv *priv, VCL_STRING hdr)
+vmod_get(VRT_CTX, VCL_ACL acl, VCL_STRING hdr)
{
- CIDRHEAD *cl = priv->priv;
unsigned u;
char const *end;
char *buf;
int i = 0;
-
+
u = WS_ReserveAll(ctx->ws);
buf = ctx->ws->f;
@@ -360,7 +89,7 @@ vmod_get(VRT_CTX, struct vmod_priv *priv, VCL_STRING hdr)
}
buf[i++] = 0;
- if (!is_trusted_ip(cl, buf)) {
+ if (!is_trusted_ip(ctx, acl, buf)) {
break;
}
end = p;

Return to:

Send suggestions and report system problems to the System administrator.