Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added set_ip_matches directive #15

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions config
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ fi

ngx_addon_name=ngx_http_set_misc_module
HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES ngx_http_set_misc_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/src/ngx_http_set_base32.c $ngx_addon_dir/src/ngx_http_set_default_value.c $ngx_addon_dir/src/ngx_http_set_hashed_upstream.c $ngx_addon_dir/src/ngx_http_set_quote_sql.c $ngx_addon_dir/src/ngx_http_set_quote_json.c $ngx_addon_dir/src/ngx_http_set_unescape_uri.c $ngx_addon_dir/src/ngx_http_set_misc_module.c $ngx_addon_dir/src/ngx_http_set_escape_uri.c $ngx_addon_dir/src/ngx_http_set_hash.c $ngx_addon_dir/src/ngx_http_set_local_today.c $ngx_addon_dir/src/ngx_http_set_hex.c $ngx_addon_dir/src/ngx_http_set_base64.c $ngx_addon_dir/src/ngx_http_set_random.c $ngx_addon_dir/src/ngx_http_set_secure_random.c $ngx_addon_dir/src/ngx_http_set_rotate.c"
NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_addon_dir/src/ddebug.h $ngx_addon_dir/src/ngx_http_set_default_value.h $ngx_addon_dir/src/ngx_http_set_hashed_upstream.h $ngx_addon_dir/src/ngx_http_set_quote_sql.h $ngx_addon_dir/src/ngx_http_set_quote_json.h $ngx_addon_dir/src/ngx_http_set_unescape_uri.h $ngx_addon_dir/src/ngx_http_set_escape_uri.h $ngx_addon_dir/src/ngx_http_set_hash.h $ngx_addon_dir/src/ngx_http_set_local_today.h $ngx_addon_dir/src/ngx_http_set_hex.h $ngx_addon_dir/src/ngx_http_set_base64.h $ngx_addon_dir/src/ngx_http_set_random.h $ngx_addon_dir/src/ngx_http_set_rotate.h $ngx_addon_dir/src/ngx_http_set_secure_random.h $ngx_addon_dir/src/ngx_http_set_misc_module.h"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/src/ngx_http_set_base32.c $ngx_addon_dir/src/ngx_http_set_default_value.c $ngx_addon_dir/src/ngx_http_set_hashed_upstream.c $ngx_addon_dir/src/ngx_http_set_quote_sql.c $ngx_addon_dir/src/ngx_http_set_quote_json.c $ngx_addon_dir/src/ngx_http_set_unescape_uri.c $ngx_addon_dir/src/ngx_http_set_misc_module.c $ngx_addon_dir/src/ngx_http_set_escape_uri.c $ngx_addon_dir/src/ngx_http_set_hash.c $ngx_addon_dir/src/ngx_http_set_local_today.c $ngx_addon_dir/src/ngx_http_set_hex.c $ngx_addon_dir/src/ngx_http_set_ip_matches.c $ngx_addon_dir/src/ngx_http_set_base64.c $ngx_addon_dir/src/ngx_http_set_random.c $ngx_addon_dir/src/ngx_http_set_secure_random.c $ngx_addon_dir/src/ngx_http_set_rotate.c"
NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_addon_dir/src/ddebug.h $ngx_addon_dir/src/ngx_http_set_default_value.h $ngx_addon_dir/src/ngx_http_set_hashed_upstream.h $ngx_addon_dir/src/ngx_http_set_quote_sql.h $ngx_addon_dir/src/ngx_http_set_quote_json.h $ngx_addon_dir/src/ngx_http_set_unescape_uri.h $ngx_addon_dir/src/ngx_http_set_escape_uri.h $ngx_addon_dir/src/ngx_http_set_hash.h $ngx_addon_dir/src/ngx_http_set_local_today.h $ngx_addon_dir/src/ngx_http_set_hex.h $ngx_addon_dir/src/ngx_http_set_ip_matches.h $ngx_addon_dir/src/ngx_http_set_base64.h $ngx_addon_dir/src/ngx_http_set_random.h $ngx_addon_dir/src/ngx_http_set_rotate.h $ngx_addon_dir/src/ngx_http_set_secure_random.h $ngx_addon_dir/src/ngx_http_set_misc_module.h"

if [ $USE_OPENSSL = YES ]; then
NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_addon_dir/src/ngx_http_set_hmac.h"
Expand Down
25 changes: 25 additions & 0 deletions doc/HttpSetMiscModule.wiki
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,31 @@ Please note that we're using [[HttpEchoModule]]'s [[HttpEchoModule#echo|echo dir

This directive requires the OpenSSL library enabled in your Nignx build (usually by passing the <code>--with-http_ssl_module</code> option to the <code>./configure</code> script).

== set_ip_matches ==
'''syntax:''' ''set_ip_matches $dst <network> <ip>''

'''default:''' ''no''

'''context:''' ''location, location if''

'''phase:''' ''rewrite''

Sets <code>$dst</code> to either <code>1</code> or <code>0</code>, dependent on whether or not the IP address (either IPv4 or IPv6) as defined in <code>ip</code> matches the network defined in <code>network</code>. The network can be specified as a single IP address or using CIDR notation.

For instance,

<geshi lang="nginx">
location /test {
set_ip_matches $r1 10.0.0.0/8 10.0.2.101;
set_ip_matches $r2 10.0.0.0/24 10.0.2.101;
echo "r1=$r1, r2=$r2";
}
</geshi>

then request <code>GET /test</code> will output <code>r1=1, r2=0</code>.

This directive looks a lot like the "allow" directive, but it executes in the "rewrite" phase and allows for custom handling of matches and mismatches.

== set_random ==
'''syntax:''' ''set_random $res <from> <to>''

Expand Down
85 changes: 85 additions & 0 deletions src/ngx_http_set_ip_matches.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#ifndef DDEBUG
#define DDEBUG 0
#endif
#include "ddebug.h"

#include <ndk.h>

#include "ngx_http_set_ip_matches.h"

ngx_int_t
ngx_http_set_misc_set_ip_matches(ngx_http_request_t *r, ngx_str_t *res,
ngx_http_variable_value_t *v)
{
ngx_http_variable_value_t *network_var, *ip_var;
ngx_str_t network_str, ip_str;
ngx_cidr_t network, ip;
size_t len;
u_char *ip_addr, *ip_mask, *network_addr, *network_mask, result;
u_int i;

network_var = v;
ip_var = v+1;

network_str.len = network_var->len;
network_str.data = network_var->data;

ip_str.len = ip_var->len;
ip_str.data = ip_var->data;

if (ngx_ptocidr(&network_str, &network) == NGX_ERROR) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "network: invalid address or cidr");
return NGX_ERROR;
}

if (ngx_ptocidr(&ip_str, &ip) == NGX_ERROR) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ip: invalid address");
return NGX_ERROR;
}

if (network.family != ip.family) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "IPv4 and IPv6 cannot be mixed");
return NGX_ERROR;
}

switch (ip.family) {
case AF_INET:
len = 4;
ip_addr = (u_char *) &ip.u.in.addr;
ip_mask = (u_char *) &ip.u.in.mask;
network_addr = (u_char *) &network.u.in.addr;
network_mask = (u_char *) &network.u.in.mask;
break;
case AF_INET6:
len = 16;
ip_addr = ip.u.in6.addr.__in6_u.__u6_addr8;
ip_mask = ip.u.in6.mask.__in6_u.__u6_addr8;
network_addr = network.u.in6.addr.__in6_u.__u6_addr8;
network_mask = network.u.in6.mask.__in6_u.__u6_addr8;
break;
default:
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "invalid address family");
return NGX_ERROR;
}

for (i=0;i<len;i++) {
if (ip_mask[i] != 255) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ip: cidr notation not allowed");
return NGX_ERROR;
}
}

result = 0;
for (i=0;i<len;i++) {
result |= (network_addr[i] & network_mask[i]) ^ (ip_addr[i] & network_mask[i]);
}

res->len = 1;
res->data = ngx_palloc(r->pool, res->len);
if (res->data == NULL) {
return NGX_ERROR;
}
res->data[0] = result==0 ? '1' : '0';

return NGX_OK;
}
11 changes: 11 additions & 0 deletions src/ngx_http_set_ip_matches.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef NGX_HTTP_SET_IP_MATCHES
#define NGX_HTTP_SET_IP_MATCHES

#include <ngx_core.h>
#include <ngx_config.h>
#include <ngx_http.h>

ngx_int_t ngx_http_set_misc_set_ip_matches(ngx_http_request_t *r,
ngx_str_t *res, ngx_http_variable_value_t *v);

#endif /* NGX_HTTP_SET_IP_MATCHES */
17 changes: 17 additions & 0 deletions src/ngx_http_set_misc_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "ngx_http_set_hash.h"
#include "ngx_http_set_hex.h"
#include "ngx_http_set_base64.h"
#include "ngx_http_set_ip_matches.h"
#if NGX_OPENSSL
#include "ngx_http_set_hmac.h"
#endif
Expand Down Expand Up @@ -62,6 +63,13 @@ static ndk_set_var_t ngx_http_set_misc_set_encode_hex_filter = {
NULL
};

static ndk_set_var_t ngx_http_set_misc_set_ip_matches_filter = {
NDK_SET_VAR_MULTI_VALUE,
(void *) ngx_http_set_misc_set_ip_matches,
2,
NULL
};


#if NGX_OPENSSL
static ndk_set_var_t ngx_http_set_misc_set_hmac_sha1_filter = {
Expand Down Expand Up @@ -315,6 +323,15 @@ static ngx_command_t ngx_http_set_misc_commands[] = {
0,
NULL
},
{
ngx_string ("set_ip_matches"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF
|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE3,
ndk_set_var_multi_value,
0,
0,
&ngx_http_set_misc_set_ip_matches_filter
},
{
ngx_string("set_hashed_upstream"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF
Expand Down
116 changes: 116 additions & 0 deletions t/ip_matches.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# vi:filetype=

use lib 'lib';
use Test::Nginx::Socket;

#repeat_each(3);

plan tests => repeat_each() * 2 * blocks();

no_long_string();

run_tests();

#no_diff();

__DATA__

=== TEST 1: IPv4 address matches IPv4 CIDR
--- config
location /bar {
set_ip_matches $ip_matches 10.0.0.0/8 10.1.0.101;
echo $ip_matches;
}
--- request
GET /bar
--- response_body
1



=== TEST 2: IPv4 address does not match IPv4 CIDR
--- config
location /bar {
set_ip_matches $ip_matches 10.0.0.0/24 10.1.0.101;
echo $ip_matches;
}
--- request
GET /bar
--- response_body
0


=== TEST 3: IPv4 address matches IPv4 address
--- config
location /bar {
set_ip_matches $ip_matches 10.1.0.101 10.1.0.101;
echo $ip_matches;
}
--- request
GET /bar
--- response_body
1



=== TEST 4: IPv4 address does not match IPv4 address
--- config
location /bar {
set_ip_matches $ip_matches 10.1.0.102 10.1.0.101 ;
echo $ip_matches;
}
--- request
GET /bar
--- response_body
0



=== TEST 5: IPv6 address matches IPv6 CIDR
--- config
location /bar {
set_ip_matches $ip_matches 3ffe::/16 3ffe:1900:4545:3:200:f8ff::67cf;
echo $ip_matches;
}
--- request
GET /bar
--- response_body
1



=== TEST 6: IPv6 address does not match IPv6 CIDR
--- config
location /bar {
set_ip_matches $ip_matches 3fff::/16 3ffe:1900:4545:3:200:f8ff::67cf;
echo $ip_matches;
}
--- request
GET /bar
--- response_body
0


=== TEST 7: IPv6 address matches IPv6 address
--- config
location /bar {
set_ip_matches $ip_matches 3ffe:1900:4545:3:200:f8ff::67cf 3ffe:1900:4545:3:200:f8ff::67cf;
echo $ip_matches;
}
--- request
GET /bar
--- response_body
1


=== TEST 7: IPv6 address does not match IPv6 address
--- config
location /bar {
set_ip_matches $ip_matches 3ffe:1900:4545:3:200:f8ff::67d0 3ffe:1900:4545:3:200:f8ff::67cf;
echo $ip_matches;
}
--- request
GET /bar
--- response_body
0