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