Hello all.

I've extended the std vmod to include an ip() method, which
converts a string into VCL IP. The result can be used for
matching against a VCL ACL.

Attached is a patch against current master. Documentation and
test case included.

Please consider this for merging into the 4.0 release.

-- 
With regards,
Lasse Karstensen
Varnish Software AS
>From ca33b40acc531ea68f20c38564cc3e647f170e40 Mon Sep 17 00:00:00 2001
From: Lasse Karstensen <lkars...@varnish-software.com>
Date: Wed, 31 Jul 2013 15:13:36 +0200
Subject: [PATCH] Implement std.ip() to simplify ACL checking in VCL

---
 bin/varnishtest/tests/m00100.vtc       |   32 ++++++++++++++++++++++++++
 doc/sphinx/reference/vmod_std.rst      |   13 +++++++++++
 lib/libvmod_std/vmod.vcc               |    1 +
 lib/libvmod_std/vmod_std_conversions.c |   39 ++++++++++++++++++++++++++++++++
 4 files changed, 85 insertions(+)
 create mode 100644 bin/varnishtest/tests/m00100.vtc

diff --git a/bin/varnishtest/tests/m00100.vtc b/bin/varnishtest/tests/m00100.vtc
new file mode 100644
index 0000000..8ed2405
--- /dev/null
+++ b/bin/varnishtest/tests/m00100.vtc
@@ -0,0 +1,32 @@
+varnishtest "test vmod_std.ip conversion"
+
+server s1 {
+	rxreq
+	txresp
+} -start
+
+varnish v1 -vcl+backend {
+	acl fooacl {
+		"192.168.2.11";
+	}
+	import std from "${topbuild}/lib/libvmod_std/.libs/libvmod_std.so" ;
+	sub vcl_recv {
+		if (std.ip(req.http.X-Forwarded-For, server.ip) !~ fooacl) {
+			return(error(403, "Forbidden"));
+		}
+	}
+	sub vcl_deliver {
+		set resp.http.x-ip = std.ip("192.168.2.10", server.ip);
+		set resp.http.x-badip = std.ip("gibberish", server.ip);
+		set resp.http.x-ipv6 = std.ip("2001:db8::10", server.ip);
+	}
+} -start
+
+client c1 {
+	txreq -url "/" -hdr "X-Forwarded-For: 192.168.2.11"
+	rxresp
+	expect resp.status == 200
+	expect resp.http.x-ip == "192.168.2.10"
+	expect resp.http.x-badip == "127.0.0.1"
+	expect resp.http.x-ipv6 == "2001:db8::10"
+} -run
diff --git a/doc/sphinx/reference/vmod_std.rst b/doc/sphinx/reference/vmod_std.rst
index f8c4456..3cf0a3c 100644
--- a/doc/sphinx/reference/vmod_std.rst
+++ b/doc/sphinx/reference/vmod_std.rst
@@ -139,6 +139,19 @@ Description
 Example
 	if (std.integer(beresp.http.x-foo, 0) > 5) { ... }
 
+ip
+--
+Prototype
+	ip(STRING s, IP fallback)
+Return value
+	IP
+Description
+    Converts the string *s* containing an IPv4 or IPv6 address to an IP.
+    If *s* fails to parse, *fallback* will be used.
+Example
+	if (std.ip(req.http.X-Forwarded-For, server.ip) !~ myacl) { return(error(403, "Forbidden")); }
+
+
 collect
 -------
 Prototype
diff --git a/lib/libvmod_std/vmod.vcc b/lib/libvmod_std/vmod.vcc
index 3238164..1f4e33e 100644
--- a/lib/libvmod_std/vmod.vcc
+++ b/lib/libvmod_std/vmod.vcc
@@ -36,3 +36,4 @@ Function STRING fileread(PRIV_CALL, STRING)
 Function DURATION duration(STRING, DURATION)
 Function INT integer(STRING, INT)
 Function VOID collect(HEADER)
+Function IP ip(STRING, IP)
diff --git a/lib/libvmod_std/vmod_std_conversions.c b/lib/libvmod_std/vmod_std_conversions.c
index c763aa3..e98b053 100644
--- a/lib/libvmod_std/vmod_std_conversions.c
+++ b/lib/libvmod_std/vmod_std_conversions.c
@@ -38,6 +38,13 @@
 #include "vrt.h"
 #include "vcc_if.h"
 
+#include <sys/socket.h>
+/* Clang 3.0 refuses to parse the gaicb struct in netdb. Works with 3.2. */
+#if __clang_major__ == 3 && __clang_minor__ == 0
+#undef __USE_GNU
+#endif
+#include <netdb.h>
+
 VCL_DURATION __match_proto__()
 vmod_duration(const struct vrt_ctx *ctx, const char *p, VCL_DURATION d)
 {
@@ -117,3 +124,35 @@ vmod_integer(const struct vrt_ctx *ctx, const char *p, VCL_INT i)
 
 	return (r);
 }
+
+
+VCL_IP __match_proto__()
+vmod_ip(const struct vrt_ctx *ctx, VCL_STRING ipstring, VCL_IP fallback) {
+	struct addrinfo hints;
+	struct addrinfo *rp;
+	struct sockaddr_storage *p;
+	unsigned u;
+	int s;
+
+	memset(&hints, 0, sizeof(struct addrinfo));
+	hints.ai_family = AF_UNSPEC;
+	hints.ai_flags = AI_NUMERICHOST; // Don't attempt DNS resolution.
+
+	s = getaddrinfo(ipstring, NULL, &hints, &rp);
+	if (s != 0) {
+		return(fallback);
+	}
+
+	u = WS_Reserve(ctx->ws, sizeof(struct sockaddr_storage));
+	if (u < sizeof(struct sockaddr_storage)) {
+		return(fallback);
+	}
+
+	p = (struct sockaddr_storage *) (void*)ctx->ws->f;
+	memcpy(p, rp->ai_addr, sizeof(struct sockaddr_storage));
+	freeaddrinfo(rp);
+
+	WS_Release(ctx->ws, sizeof(struct sockaddr_storage));
+	return(p);
+}
+
-- 
1.7.10.4

_______________________________________________
varnish-dev mailing list
varnish-dev@varnish-cache.org
https://www.varnish-cache.org/lists/mailman/listinfo/varnish-dev

Reply via email to