/*
* Copyright (C) 2013-2015 Tobias Brunner
+ * Copyright (C) 2016 Andreas Steffen
* Copyright (C) 2009 Martin Willi
- * Hochschule fuer Technik Rapperswil
+ * HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
} data;
} result;
} string_data[] = {
- {NULL, ID_ANY, { .type = ENC_CHUNK }},
- {"", ID_ANY, { .type = ENC_CHUNK }},
- {"%any", ID_ANY, { .type = ENC_CHUNK }},
- {"%any6", ID_ANY, { .type = ENC_CHUNK }},
- {"0.0.0.0", ID_ANY, { .type = ENC_CHUNK }},
- {"0::0", ID_ANY, { .type = ENC_CHUNK }},
- {"::", ID_ANY, { .type = ENC_CHUNK }},
- {"*", ID_ANY, { .type = ENC_CHUNK }},
- {"any", ID_FQDN, { .type = ENC_SIMPLE }},
- {"any6", ID_FQDN, { .type = ENC_SIMPLE }},
- {"0", ID_FQDN, { .type = ENC_SIMPLE }},
- {"**", ID_FQDN, { .type = ENC_SIMPLE }},
- {"192.168.1.1", ID_IPV4_ADDR, { .type = ENC_CHUNK,
+ {NULL, ID_ANY, { .type = ENC_CHUNK }},
+ {"", ID_ANY, { .type = ENC_CHUNK }},
+ {"%any", ID_ANY, { .type = ENC_CHUNK }},
+ {"%any6", ID_ANY, { .type = ENC_CHUNK }},
+ {"0.0.0.0", ID_ANY, { .type = ENC_CHUNK }},
+ {"0::0", ID_ANY, { .type = ENC_CHUNK }},
+ {"::", ID_ANY, { .type = ENC_CHUNK }},
+ {"*", ID_ANY, { .type = ENC_CHUNK }},
+ {"any", ID_FQDN, { .type = ENC_SIMPLE }},
+ {"any6", ID_FQDN, { .type = ENC_SIMPLE }},
+ {"0", ID_FQDN, { .type = ENC_SIMPLE }},
+ {"**", ID_FQDN, { .type = ENC_SIMPLE }},
+ {"192.168.1.1", ID_IPV4_ADDR, { .type = ENC_CHUNK,
.data.c = chunk_from_chars(0xc0,0xa8,0x01,0x01) }},
- {"192.168.", ID_FQDN, { .type = ENC_SIMPLE }},
- {".", ID_FQDN, { .type = ENC_SIMPLE }},
- {"fec0::1", ID_IPV6_ADDR, { .type = ENC_CHUNK,
+ {"192.168.", ID_FQDN, { .type = ENC_SIMPLE }},
+ {".", ID_FQDN, { .type = ENC_SIMPLE }},
+ {"192.168.1.1/33", ID_FQDN, { .type = ENC_SIMPLE }},
+ {"192.168.1.1/32", ID_IPV4_ADDR_SUBNET, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0xc0,0xa8,0x01,0x01,0xff,0xff,0xff,0xff) }},
+ {"192.168.1.1/31", ID_IPV4_ADDR_SUBNET, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0xc0,0xa8,0x01,0x00,0xff,0xff,0xff,0xfe) }},
+ {"192.168.1.8/30", ID_IPV4_ADDR_SUBNET, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0xc0,0xa8,0x01,0x08,0xff,0xff,0xff,0xfc) }},
+ {"192.168.1.128/25", ID_IPV4_ADDR_SUBNET, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0xc0,0xa8,0x01,0x80,0xff,0xff,0xff,0x80) }},
+ {"192.168.1.0/24", ID_IPV4_ADDR_SUBNET, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0xc0,0xa8,0x01,0x00,0xff,0xff,0xff,0x00) }},
+ {"192.168.1.0/23", ID_IPV4_ADDR_SUBNET, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0xc0,0xa8,0x00,0x00,0xff,0xff,0xfe,0x00) }},
+ {"192.168.4.0/22", ID_IPV4_ADDR_SUBNET, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0xc0,0xa8,0x04,0x00,0xff,0xff,0xfc,0x00) }},
+ {"0.0.0.0/0", ID_IPV4_ADDR_SUBNET, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00) }},
+ {"192.168.1.0-192.168.1.40",ID_IPV4_ADDR_RANGE, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0xc0,0xa8,0x01,0x00,0xc0,0xa8,0x01,0x28) }},
+ {"0.0.0.0-255.255.255.255", ID_IPV4_ADDR_RANGE, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff) }},
+ {"192.168.1.40-192.168.1.0",ID_FQDN, { .type = ENC_SIMPLE }},
+ {"fec0::1", ID_IPV6_ADDR, { .type = ENC_CHUNK,
.data.c = chunk_from_chars(0xfe,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01) }},
- {"fec0::", ID_IPV6_ADDR, { .type = ENC_CHUNK,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01) }},
+ {"fec0::", ID_IPV6_ADDR, { .type = ENC_CHUNK,
.data.c = chunk_from_chars(0xfe,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00) }},
- {"fec0:", ID_KEY_ID, { .type = ENC_SIMPLE }},
- {":", ID_KEY_ID, { .type = ENC_SIMPLE }},
- {"alice@strongswan.org", ID_RFC822_ADDR, { .type = ENC_SIMPLE }},
- {"alice@strongswan", ID_RFC822_ADDR, { .type = ENC_SIMPLE }},
- {"alice@", ID_RFC822_ADDR, { .type = ENC_SIMPLE }},
- {"alice", ID_FQDN, { .type = ENC_SIMPLE }},
- {"@", ID_FQDN, { .type = ENC_CHUNK }},
- {" @", ID_RFC822_ADDR, { .type = ENC_SIMPLE }},
- {"@strongswan.org", ID_FQDN, { .type = ENC_STRING,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00) }},
+ {"fec0:", ID_KEY_ID, { .type = ENC_SIMPLE }},
+ {":", ID_KEY_ID, { .type = ENC_SIMPLE }},
+ {"fec0::1/129", ID_KEY_ID, { .type = ENC_SIMPLE }},
+ {"fec0::1/128", ID_IPV6_ADDR_SUBNET, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0xfe,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ) }},
+ {"fec0::1/127", ID_IPV6_ADDR_SUBNET, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0xfe,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe ) }},
+ {"fec0::4/126", ID_IPV6_ADDR_SUBNET, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0xfe,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc ) }},
+ {"fec0::100/120", ID_IPV6_ADDR_SUBNET, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0xfe,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 ) }},
+ {"::/0", ID_IPV6_ADDR_SUBNET, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ) }},
+ {"fec0::1-fec0::4fff", ID_IPV6_ADDR_RANGE, { .type = ENC_CHUNK,
+ .data.c = chunk_from_chars(0xfe,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
+ 0xfe,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x4f,0xff ) }},
+ {"fec0::4fff-fec0::1", ID_KEY_ID, { .type = ENC_SIMPLE }},
+ {"fec0::1-", ID_KEY_ID, { .type = ENC_SIMPLE }},
+ {"alice@strongswan.org", ID_RFC822_ADDR, { .type = ENC_SIMPLE }},
+ {"alice@strongswan", ID_RFC822_ADDR, { .type = ENC_SIMPLE }},
+ {"alice@", ID_RFC822_ADDR, { .type = ENC_SIMPLE }},
+ {"alice", ID_FQDN, { .type = ENC_SIMPLE }},
+ {"@", ID_FQDN, { .type = ENC_CHUNK }},
+ {" @", ID_RFC822_ADDR, { .type = ENC_SIMPLE }},
+ {"@strongswan.org", ID_FQDN, { .type = ENC_STRING,
.data.s = "strongswan.org" }},
- {"@#deadbeef", ID_KEY_ID, { .type = ENC_CHUNK,
+ {"@#deadbeef", ID_KEY_ID, { .type = ENC_CHUNK,
.data.c = chunk_from_chars(0xde,0xad,0xbe,0xef) }},
- {"@#deadbee", ID_KEY_ID, { .type = ENC_CHUNK,
+ {"@#deadbee", ID_KEY_ID, { .type = ENC_CHUNK,
.data.c = chunk_from_chars(0x0d,0xea,0xdb,0xee) }},
- {"foo=bar", ID_KEY_ID, { .type = ENC_SIMPLE }},
- {"foo=", ID_KEY_ID, { .type = ENC_SIMPLE }},
- {"=bar", ID_KEY_ID, { .type = ENC_SIMPLE }},
- {"C=", ID_DER_ASN1_DN, { .type = ENC_CHUNK,
+ {"foo=bar", ID_KEY_ID, { .type = ENC_SIMPLE }},
+ {"foo=", ID_KEY_ID, { .type = ENC_SIMPLE }},
+ {"=bar", ID_KEY_ID, { .type = ENC_SIMPLE }},
+ {"C=", ID_DER_ASN1_DN, { .type = ENC_CHUNK,
.data.c = chunk_from_chars(0x30,0x0b,0x31,0x09,0x30,0x07,0x06,
0x03,0x55,0x04,0x06,0x13,0x00) }},
- {"C=CH", ID_DER_ASN1_DN, { .type = ENC_CHUNK,
+ {"C=CH", ID_DER_ASN1_DN, { .type = ENC_CHUNK,
.data.c = chunk_from_chars(0x30,0x0d,0x31,0x0b,0x30,0x09,0x06,
0x03,0x55,0x04,0x06,0x13,0x02,0x43,0x48) }},
- {"C=CH,", ID_DER_ASN1_DN, { .type = ENC_CHUNK,
+ {"C=CH,", ID_DER_ASN1_DN, { .type = ENC_CHUNK,
.data.c = chunk_from_chars(0x30,0x0d,0x31,0x0b,0x30,0x09,0x06,
0x03,0x55,0x04,0x06,0x13,0x02,0x43,0x48) }},
- {"C=CH, ", ID_DER_ASN1_DN, { .type = ENC_CHUNK,
+ {"C=CH, ", ID_DER_ASN1_DN, { .type = ENC_CHUNK,
.data.c = chunk_from_chars(0x30,0x0d,0x31,0x0b,0x30,0x09,0x06,
0x03,0x55,0x04,0x06,0x13,0x02,0x43,0x48) }},
- {"C=CH, O", ID_KEY_ID, { .type = ENC_SIMPLE }},
- {"IPv4:#c0a80101", ID_IPV4_ADDR, { .type = ENC_CHUNK,
+ {"C=CH, O", ID_KEY_ID, { .type = ENC_SIMPLE }},
+ {"IPv4:#c0a80101", ID_IPV4_ADDR, { .type = ENC_CHUNK,
.data.c = chunk_from_chars(0xc0,0xa8,0x01,0x01) }},
- { "email:tester", ID_RFC822_ADDR, { .type = ENC_STRING,
+ { "email:tester", ID_RFC822_ADDR, { .type = ENC_STRING,
.data.s = "tester" }},
- { "{1}:#c0a80101", ID_IPV4_ADDR, { .type = ENC_CHUNK,
+ { "{1}:#c0a80101", ID_IPV4_ADDR, { .type = ENC_CHUNK,
.data.c = chunk_from_chars(0xc0,0xa8,0x01,0x01) }},
- { "{0x02}:tester", ID_FQDN, { .type = ENC_STRING,
+ { "{0x02}:tester", ID_FQDN, { .type = ENC_STRING,
.data.s = "tester" }},
- { "{99}:somedata", 99, { .type = ENC_STRING,
+ { "{99}:somedata", 99, { .type = ENC_STRING,
.data.s = "somedata" }},
};
string_equals("192.168.1.1", "192.168.1.1");
string_equals_id("(invalid ID_IPV4_ADDR)",
- identification_create_from_encoding(ID_IPV4_ADDR, chunk_empty));
+ identification_create_from_encoding(ID_IPV4_ADDR, chunk_empty));
+ string_equals("192.168.1.1/32", "192.168.1.1/32");
+ string_equals("192.168.1.2/31", "192.168.1.2/31");
+ string_equals("192.168.1.0/24", "192.168.1.0/24");
+ string_equals("192.168.2.0/23", "192.168.2.0/23");
+ string_equals("0.0.0.0/0", "0.0.0.0/0");
+ string_equals_id("(invalid ID_IPV4_ADDR_SUBNET)",
+ identification_create_from_encoding(ID_IPV4_ADDR_SUBNET, chunk_empty));
+ string_equals("192.168.1.1-192.168.1.254", "192.168.1.1-192.168.1.254");
+ string_equals("0.0.0.0-255.255.255.255", "0.0.0.0-255.255.255.255");
+ string_equals_id("(invalid ID_IPV4_ADDR_RANGE)",
+ identification_create_from_encoding(ID_IPV4_ADDR_RANGE, chunk_empty));
string_equals("fec0::1", "fec0::1");
string_equals("fec0::1", "fec0:0:0::1");
string_equals_id("(invalid ID_IPV6_ADDR)",
- identification_create_from_encoding(ID_IPV6_ADDR, chunk_empty));
-
+ identification_create_from_encoding(ID_IPV6_ADDR, chunk_empty));
+ string_equals("fec0::1/128", "fec0::1/128");
+ string_equals("fec0::2/127", "fec0::2/127");
+ string_equals("fec0::100/120", "fec0::100/120");
+ string_equals("::/0", "::/0");
+ string_equals_id("(invalid ID_IPV6_ADDR_SUBNET)",
+ identification_create_from_encoding(ID_IPV6_ADDR_SUBNET, chunk_empty));
+ string_equals("fec0::1-fec0::4fff", "fec0::1-fec0::4fff");
+ string_equals_id("(invalid ID_IPV6_ADDR_RANGE)",
+ identification_create_from_encoding(ID_IPV6_ADDR_RANGE, chunk_empty));
string_equals_id("(unknown ID type: 255)",
- identification_create_from_encoding(255, chunk_empty));
+ identification_create_from_encoding(255, chunk_empty));
string_equals("moon@strongswan.org", "moon@strongswan.org");
string_equals("MOON@STRONGSWAN.ORG", "MOON@STRONGSWAN.ORG");
}
END_TEST
+START_TEST(test_matches_range)
+{
+ identification_t *a, *b;
+
+ /* IPv4 addresses */
+ a = identification_create_from_string("192.168.1.1");
+ ck_assert(a->get_type(a) == ID_IPV4_ADDR);
+ ck_assert(id_matches(a, "%any", ID_MATCH_ANY));
+ ck_assert(id_matches(a, "0.0.0.0/0", ID_MATCH_MAX_WILDCARDS));
+ ck_assert(id_matches(a, "192.168.1.1", ID_MATCH_PERFECT));
+ ck_assert(id_matches(a, "192.168.1.2", ID_MATCH_NONE));
+ ck_assert(id_matches(a, "192.168.1.1/32", ID_MATCH_PERFECT));
+ ck_assert(id_matches(a, "192.168.1.0/32", ID_MATCH_NONE));
+ ck_assert(id_matches(a, "192.168.1.0/24", ID_MATCH_ONE_WILDCARD));
+ ck_assert(id_matches(a, "192.168.0.0/24", ID_MATCH_NONE));
+ ck_assert(id_matches(a, "192.168.1.1-192.168.1.1", ID_MATCH_PERFECT));
+ ck_assert(id_matches(a, "192.168.1.0-192.168.1.64", ID_MATCH_ONE_WILDCARD));
+ ck_assert(id_matches(a, "192.168.1.2-192.168.1.64", ID_MATCH_NONE));
+ ck_assert(id_matches(a, "192.168.0.240-192.168.1.0", ID_MATCH_NONE));
+ ck_assert(id_matches(a, "foo@bar", ID_MATCH_NONE));
+
+ /* Malformed IPv4 subnet and range encoding */
+ b = identification_create_from_encoding(ID_IPV4_ADDR_SUBNET, chunk_empty);
+ ck_assert(a->matches(a, b) == ID_MATCH_NONE);
+ b->destroy(b);
+ b = identification_create_from_encoding(ID_IPV4_ADDR_RANGE, chunk_empty);
+ ck_assert(a->matches(a, b) == ID_MATCH_NONE);
+ b->destroy(b);
+ b = identification_create_from_encoding(ID_IPV4_ADDR_RANGE,
+ chunk_from_chars(0xc0,0xa8,0x01,0x28,0xc0,0xa8,0x01,0x00));
+ ck_assert(a->matches(a, b) == ID_MATCH_NONE);
+ b->destroy(b);
+
+ a->destroy(a);
+
+ /* IPv6 addresses */
+ a = identification_create_from_string("fec0::1");
+ ck_assert(a->get_type(a) == ID_IPV6_ADDR);
+ ck_assert(id_matches(a, "%any", ID_MATCH_ANY));
+ ck_assert(id_matches(a, "::/0", ID_MATCH_MAX_WILDCARDS));
+ ck_assert(id_matches(a, "fec0::1", ID_MATCH_PERFECT));
+ ck_assert(id_matches(a, "fec0::2", ID_MATCH_NONE));
+ ck_assert(id_matches(a, "fec0::1/128", ID_MATCH_PERFECT));
+ ck_assert(id_matches(a, "fec0::/128", ID_MATCH_NONE));
+ ck_assert(id_matches(a, "fec0::/120", ID_MATCH_ONE_WILDCARD));
+ ck_assert(id_matches(a, "fec0::100/120", ID_MATCH_NONE));
+ ck_assert(id_matches(a, "fec0::1-fec0::1", ID_MATCH_PERFECT));
+ ck_assert(id_matches(a, "fec0::0-fec0::5", ID_MATCH_ONE_WILDCARD));
+ ck_assert(id_matches(a, "fec0::4001-fec0::4ffe", ID_MATCH_NONE));
+ ck_assert(id_matches(a, "feb0::1-fec0::0", ID_MATCH_NONE));
+ ck_assert(id_matches(a, "foo@bar", ID_MATCH_NONE));
+
+ /* Malformed IPv6 subnet and range encoding */
+ b = identification_create_from_encoding(ID_IPV6_ADDR_SUBNET, chunk_empty);
+ ck_assert(a->matches(a, b) == ID_MATCH_NONE);
+ b->destroy(b);
+ b = identification_create_from_encoding(ID_IPV6_ADDR_RANGE, chunk_empty);
+ ck_assert(a->matches(a, b) == ID_MATCH_NONE);
+ b->destroy(b);
+ b = identification_create_from_encoding(ID_IPV6_ADDR_RANGE,
+ chunk_from_chars(0xfe,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x4f,0xff,
+ 0xfe,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 ));
+ ck_assert(a->matches(a, b) == ID_MATCH_NONE);
+ b->destroy(b);
+
+ a->destroy(a);
+
+ /* Malformed IPv4 address encoding */
+ a = identification_create_from_encoding(ID_IPV4_ADDR, chunk_empty);
+ ck_assert(id_matches(a, "0.0.0.0/0", ID_MATCH_NONE));
+ ck_assert(id_matches(a, "0.0.0.0-255.255.255.255", ID_MATCH_NONE));
+ a->destroy(a);
+
+ /* Malformed IPv6 address encoding */
+ a = identification_create_from_encoding(ID_IPV6_ADDR, chunk_empty);
+ ck_assert(id_matches(a, "::/0", ID_MATCH_NONE));
+ ck_assert(id_matches(a, "::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", ID_MATCH_NONE));
+ a->destroy(a);
+}
+END_TEST
+
START_TEST(test_matches_string)
{
identification_t *a;
tcase_add_test(tc, test_matches);
tcase_add_test(tc, test_matches_any);
tcase_add_test(tc, test_matches_binary);
+ tcase_add_test(tc, test_matches_range);
tcase_add_test(tc, test_matches_string);
tcase_add_loop_test(tc, test_matches_empty, ID_ANY, ID_KEY_ID + 1);
tcase_add_loop_test(tc, test_matches_empty_reverse, ID_ANY, ID_KEY_ID + 1);
/*
+ * Copyright (C) 2016 Andreas Steffen
* Copyright (C) 2009-2015 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
- * Hochschule fuer Technik Rapperswil
+ * HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
}
/**
+ * Transform netmask to CIDR bits
+ */
+static int netmask_to_cidr(char *netmask, size_t address_size)
+{
+ uint8_t byte;
+ int i, netbits = 0;
+
+ for (i = 0; i < address_size; i++)
+ {
+ byte = netmask[i];
+
+ if (byte == 0x00)
+ {
+ break;
+ }
+ if (byte == 0xff)
+ {
+ netbits += 8;
+ }
+ else
+ {
+ while (byte & 0x80)
+ {
+ netbits++;
+ byte <<= 1;
+ }
+ }
+ }
+ return netbits;
+}
+
+METHOD(identification_t, matches_range, id_match_t,
+ private_identification_t *this, identification_t *other)
+{
+ chunk_t other_encoding;
+ uint8_t *address, *from, *to, *network, *netmask;
+ size_t address_size = 0;
+ int netbits, range_sign, i;
+
+ if (other->get_type(other) == ID_ANY)
+ {
+ return ID_MATCH_ANY;
+ }
+ if (this->type == other->get_type(other) &&
+ chunk_equals(this->encoded, other->get_encoding(other)))
+ {
+ return ID_MATCH_PERFECT;
+ }
+ if ((this->type == ID_IPV4_ADDR &&
+ other->get_type(other) == ID_IPV4_ADDR_SUBNET))
+ {
+ address_size = sizeof(struct in_addr);
+ }
+ else if ((this->type == ID_IPV6_ADDR &&
+ other->get_type(other) == ID_IPV6_ADDR_SUBNET))
+ {
+ address_size = sizeof(struct in6_addr);
+ }
+ if (address_size)
+ {
+ other_encoding = other->get_encoding(other);
+ if (this->encoded.len != address_size ||
+ other_encoding.len != 2 * address_size)
+ {
+ return ID_MATCH_NONE;
+ }
+ address = this->encoded.ptr;
+ network = other_encoding.ptr;
+ netmask = other_encoding.ptr + address_size;
+ netbits = netmask_to_cidr(netmask, address_size);
+
+ if (netbits == 0)
+ {
+ return ID_MATCH_MAX_WILDCARDS;
+ }
+ if (netbits == 8 * address_size)
+ {
+ return memeq(address, network, address_size) ?
+ ID_MATCH_PERFECT : ID_MATCH_NONE;
+ }
+ for (i = 0; i < (netbits + 7)/8; i++)
+ {
+ if ((address[i] ^ network[i]) & netmask[i])
+ {
+ return ID_MATCH_NONE;
+ }
+ }
+ return ID_MATCH_ONE_WILDCARD;
+ }
+ if ((this->type == ID_IPV4_ADDR &&
+ other->get_type(other) == ID_IPV4_ADDR_RANGE))
+ {
+ address_size = sizeof(struct in_addr);
+ }
+ else if ((this->type == ID_IPV6_ADDR &&
+ other->get_type(other) == ID_IPV6_ADDR_RANGE))
+ {
+ address_size = sizeof(struct in6_addr);
+ }
+ if (address_size)
+ {
+ other_encoding = other->get_encoding(other);
+ if (this->encoded.len != address_size ||
+ other_encoding.len != 2 * address_size)
+ {
+ return ID_MATCH_NONE;
+ }
+ address = this->encoded.ptr;
+ from = other_encoding.ptr;
+ to = other_encoding.ptr + address_size;
+
+ range_sign = memcmp(to, from, address_size);
+ if (range_sign < 0)
+ { /* to is smaller than from */
+ return ID_MATCH_NONE;
+ }
+
+ /* check lower bound */
+ for (i = 0; i < address_size; i++)
+ {
+ if (address[i] != from[i])
+ {
+ if (address[i] < from[i])
+ {
+ return ID_MATCH_NONE;
+ }
+ break;
+ }
+ }
+
+ /* check upper bound */
+ for (i = 0; i < address_size; i++)
+ {
+ if (address[i] != to[i])
+ {
+ if (address[i] > to[i])
+ {
+ return ID_MATCH_NONE;
+ }
+ break;
+ }
+ }
+ return range_sign ? ID_MATCH_ONE_WILDCARD : ID_MATCH_PERFECT;
+ }
+ return ID_MATCH_NONE;
+}
+
+/**
* Described in header.
*/
int identification_printf_hook(printf_hook_data_t *data,
{
private_identification_t *this = *((private_identification_t**)(args[0]));
chunk_t proper;
- char buf[512];
+ char buf[BUF_LEN];
+ char *pos;
+ size_t written, len, address_size;
if (this == NULL)
{
switch (this->type)
{
case ID_ANY:
- snprintf(buf, sizeof(buf), "%%any");
+ snprintf(buf, BUF_LEN, "%%any");
break;
case ID_IPV4_ADDR:
if (this->encoded.len < sizeof(struct in_addr) ||
- inet_ntop(AF_INET, this->encoded.ptr, buf, sizeof(buf)) == NULL)
+ inet_ntop(AF_INET, this->encoded.ptr, buf, BUF_LEN) == NULL)
+ {
+ snprintf(buf, BUF_LEN, "(invalid ID_IPV4_ADDR)");
+ }
+ break;
+ case ID_IPV4_ADDR_SUBNET:
+ address_size = sizeof(struct in_addr);
+ if (this->encoded.len < 2 * address_size ||
+ inet_ntop(AF_INET, this->encoded.ptr, buf, BUF_LEN) == NULL)
+ {
+ snprintf(buf, BUF_LEN, "(invalid ID_IPV4_ADDR_SUBNET)");
+ break;
+ }
+ written = strlen(buf);
+ snprintf(buf + written, BUF_LEN - written, "/%d",
+ netmask_to_cidr(this->encoded.ptr + address_size,
+ address_size));
+ break;
+ case ID_IPV4_ADDR_RANGE:
+ address_size = sizeof(struct in_addr);
+ if (this->encoded.len < 2 * address_size ||
+ inet_ntop(AF_INET, this->encoded.ptr, buf, BUF_LEN) == NULL)
{
- snprintf(buf, sizeof(buf), "(invalid ID_IPV4_ADDR)");
+ snprintf(buf, BUF_LEN, "(invalid ID_IPV4_ADDR_RANGE)");
+ break;
+ }
+ written = strlen(buf);
+ pos = buf + written;
+ len = BUF_LEN - written;
+ written = snprintf(pos, len, "-");
+ if (written < 0 || written >= len ||
+ inet_ntop(AF_INET, this->encoded.ptr + address_size,
+ pos + written, len - written) == NULL)
+ {
+ snprintf(buf, BUF_LEN, "(invalid ID_IPV4_ADDR_RANGE)");
}
break;
case ID_IPV6_ADDR:
if (this->encoded.len < sizeof(struct in6_addr) ||
- inet_ntop(AF_INET6, this->encoded.ptr, buf, INET6_ADDRSTRLEN) == NULL)
+ inet_ntop(AF_INET6, this->encoded.ptr, buf, BUF_LEN) == NULL)
+ {
+ snprintf(buf, BUF_LEN, "(invalid ID_IPV6_ADDR)");
+ }
+ break;
+ case ID_IPV6_ADDR_SUBNET:
+ address_size = sizeof(struct in6_addr);
+ if (this->encoded.len < 2 * address_size ||
+ inet_ntop(AF_INET6, this->encoded.ptr, buf, BUF_LEN) == NULL)
+ {
+ snprintf(buf, BUF_LEN, "(invalid ID_IPV6_ADDR_SUBNET)");
+ }
+ else
{
- snprintf(buf, sizeof(buf), "(invalid ID_IPV6_ADDR)");
+ written = strlen(buf);
+ snprintf(buf + written, BUF_LEN - written, "/%d",
+ netmask_to_cidr(this->encoded.ptr + address_size,
+ address_size));
+ }
+ break;
+ case ID_IPV6_ADDR_RANGE:
+ address_size = sizeof(struct in6_addr);
+ if (this->encoded.len < 2 * address_size ||
+ inet_ntop(AF_INET6, this->encoded.ptr, buf, BUF_LEN) == NULL)
+ {
+ snprintf(buf, BUF_LEN, "(invalid ID_IPV6_ADDR_RANGE)");
+ break;
+ }
+ written = strlen(buf);
+ pos = buf + written;
+ len = BUF_LEN - written;
+ written = snprintf(pos, len, "-");
+ if (written < 0 || written >= len ||
+ inet_ntop(AF_INET6, this->encoded.ptr + address_size,
+ pos + written, len - written) == NULL)
+ {
+ snprintf(buf, BUF_LEN, "(invalid ID_IPV6_ADDR_RANGE)");
}
break;
case ID_FQDN:
case ID_RFC822_ADDR:
case ID_DER_ASN1_GN_URI:
chunk_printable(this->encoded, &proper, '?');
- snprintf(buf, sizeof(buf), "%.*s", (int)proper.len, proper.ptr);
+ snprintf(buf, BUF_LEN, "%.*s", (int)proper.len, proper.ptr);
chunk_free(&proper);
break;
case ID_DER_ASN1_DN:
- dntoa(this->encoded, buf, sizeof(buf));
+ dntoa(this->encoded, buf, BUF_LEN);
break;
case ID_DER_ASN1_GN:
- snprintf(buf, sizeof(buf), "(ASN.1 general name)");
+ snprintf(buf, BUF_LEN, "(ASN.1 general name)");
break;
case ID_KEY_ID:
if (chunk_printable(this->encoded, NULL, '?') &&
this->encoded.len != HASH_SIZE_SHA1)
{ /* fully printable, use ascii version */
- snprintf(buf, sizeof(buf), "%.*s", (int)this->encoded.len,
+ snprintf(buf, BUF_LEN, "%.*s", (int)this->encoded.len,
this->encoded.ptr);
}
else
{ /* not printable, hex dump */
- snprintf(buf, sizeof(buf), "%#B", &this->encoded);
+ snprintf(buf, BUF_LEN, "%#B", &this->encoded);
}
break;
default:
- snprintf(buf, sizeof(buf), "(unknown ID type: %d)", this->type);
+ snprintf(buf, BUF_LEN, "(unknown ID type: %d)", this->type);
break;
}
if (spec->minus)
this->public.matches = _matches_dn;
this->public.contains_wildcards = _contains_wildcards_dn;
break;
+ case ID_IPV4_ADDR:
+ case ID_IPV6_ADDR:
+ this->public.hash = _hash_binary;
+ this->public.equals = _equals_binary;
+ this->public.matches = _matches_range;
+ this->public.contains_wildcards = return_false;
+ break;
default:
this->public.hash = _hash_binary;
this->public.equals = _equals_binary;
} prefixes[] = {
{ "ipv4:", ID_IPV4_ADDR },
{ "ipv6:", ID_IPV6_ADDR },
+ { "ipv4net:", ID_IPV4_ADDR_SUBNET },
+ { "ipv6net:", ID_IPV6_ADDR_SUBNET },
+ { "ipv4range:", ID_IPV4_ADDR_RANGE },
+ { "ipv6range:", ID_IPV6_ADDR_RANGE },
{ "rfc822:", ID_RFC822_ADDR },
{ "email:", ID_RFC822_ADDR },
{ "userfqdn:", ID_USER_FQDN },
return this;
}
+/**
+ * Convert to an IPv4/IPv6 host address, subnet or address range
+ */
+static private_identification_t* create_ip_address_from_string(char *string,
+ bool is_ipv4)
+{
+ private_identification_t *this;
+ uint8_t encoding[32];
+ uint8_t *str, *pos, *address, *to_address, *netmask;
+ size_t address_size;
+ int bits, bytes, i;
+ bool has_subnet = FALSE, has_range = FALSE;
+
+ address = encoding;
+ address_size = is_ipv4 ? sizeof(struct in_addr) : sizeof(struct in6_addr);
+
+ str = strdup(string);
+ pos = strchr(str, '/');
+ if (pos)
+ { /* separate IP address from optional netmask */
+
+ *pos = '\0';
+ has_subnet = TRUE;
+ }
+ else
+ {
+ pos = strchr(str, '-');
+ if (pos)
+ { /* separate lower address from upper address of IP range */
+ *pos = '\0';
+ has_range = TRUE;
+ }
+ }
+
+ if (inet_pton(is_ipv4 ? AF_INET : AF_INET6, str, address) != 1)
+ {
+ free(str);
+ return NULL;
+ }
+
+ if (has_subnet)
+ { /* is IP subnet */
+ bits = atoi(pos + 1);
+ if (bits > 8 * address_size)
+ {
+ free(str);
+ return NULL;
+ }
+ bytes = bits / 8;
+ bits -= 8 * bytes;
+ netmask = encoding + address_size;
+
+ for (i = 0; i < address_size; i++)
+ {
+ if (bytes)
+ {
+ *netmask = 0xff;
+ bytes--;
+ }
+ else if (bits)
+ {
+ *netmask = 0xff << (8 - bits);
+ bits = 0;
+ }
+ else
+ {
+ *netmask = 0x00;
+ }
+ *address++ &= *netmask++;
+ }
+ this = identification_create(is_ipv4 ? ID_IPV4_ADDR_SUBNET :
+ ID_IPV6_ADDR_SUBNET);
+ this->encoded = chunk_clone(chunk_create(encoding, 2 * address_size));
+ }
+ else if (has_range)
+ { /* is IP range */
+ to_address = encoding + address_size;
+
+ if (inet_pton(is_ipv4 ? AF_INET : AF_INET6, pos + 1, to_address) != 1)
+ {
+ free(str);
+ return NULL;
+ }
+ for (i = 0; i < address_size; i++)
+ {
+ if (address[i] != to_address[i])
+ {
+ if (address[i] > to_address[i])
+ {
+ free(str);
+ return NULL;
+ }
+ break;
+ }
+ }
+ this = identification_create(is_ipv4 ? ID_IPV4_ADDR_RANGE :
+ ID_IPV6_ADDR_RANGE);
+ this->encoded = chunk_clone(chunk_create(encoding, 2 * address_size));
+ }
+ else
+ { /* is IP host address */
+ this = identification_create(is_ipv4 ? ID_IPV4_ADDR : ID_IPV6_ADDR);
+ this->encoded = chunk_clone(chunk_create(encoding, address_size));
+ }
+ free(str);
+
+ return this;
+}
+
/*
* Described in header.
*/
{
if (strchr(string, ':') == NULL)
{
- struct in_addr address;
- chunk_t chunk = {(void*)&address, sizeof(address)};
-
- if (inet_pton(AF_INET, string, &address) > 0)
- { /* is IPv4 */
- this = identification_create(ID_IPV4_ADDR);
- this->encoded = chunk_clone(chunk);
- }
- else
+ /* IPv4 address or subnet */
+ this = create_ip_address_from_string(string, TRUE);
+ if (!this)
{ /* not IPv4, mostly FQDN */
this = identification_create(ID_FQDN);
this->encoded = chunk_from_str(strdup(string));
}
else
{
- struct in6_addr address;
- chunk_t chunk = {(void*)&address, sizeof(address)};
-
- if (inet_pton(AF_INET6, string, &address) > 0)
- { /* is IPv6 */
- this = identification_create(ID_IPV6_ADDR);
- this->encoded = chunk_clone(chunk);
- }
- else
+ /* IPv6 address or subnet */
+ this = create_ip_address_from_string(string, FALSE);
+ if (!this)
{ /* not IPv4/6 fallback to KEY_ID */
this = identification_create(ID_KEY_ID);
this->encoded = chunk_from_str(strdup(string));