summaryrefslogtreecommitdiffstats
path: root/scramble_wlw.c
blob: ac52718f652fb5450c038ccd36b6b6a7a3b09523 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include "scramble_wlw.h"
#include "patricia.h"
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#define PREFIX_DELIMITER ",; "

static patricia_tree_t *tree4 = NULL;
static patricia_tree_t *tree6 = NULL;
static prefix_t lookup_pfix4;
static prefix_t lookup_pfix6;
static scrambler_ip4_t _scrambler_ip4 = NULL;
static scrambler_ip6_t _scrambler_ip6 = NULL;


static inline int
scramble_wlw_lookup_addr4(const struct in_addr *sin) {
    if (tree4 == NULL)
        return 0;
    memcpy(&lookup_pfix4.add.sin, sin, sizeof(*sin));
    return (patricia_search_best2(tree4, &lookup_pfix4, 1) != NULL);
}

static inline int
scramble_wlw_lookup_addr6(const struct in6_addr *sin6) {
    if (tree6 == NULL)
        return 0;
    memcpy(&lookup_pfix6.add.sin6, sin6, sizeof(*sin6));
    return (patricia_search_best2(tree6, &lookup_pfix6, 1) != NULL);
}

/* Init white list wrapper.  Can be called again to add wl-state.
 * prefix_wlist is a list of ip4 and ip6 prefixes, separated by
 * one of the PREFIX_DELIMITER
 * s4 is an ipv4 address scrambler
 * s6 is an ipv6 address scrambler
 */
void
scramble_wlw_init(const char *prefix_wlist, scrambler_ip4_t s4, scrambler_ip6_t s6) {
    char *plist = strdup(prefix_wlist), *cp;
    int afam, bits;
    patricia_tree_t **tree;

    _scrambler_ip4 = s4;
    _scrambler_ip6 = s6;

    for (cp = strtok(plist, PREFIX_DELIMITER); cp != NULL; cp = strtok(NULL, PREFIX_DELIMITER)) {
        if (index(cp, ':') == NULL) {
            tree = &tree4;
            afam = AF_INET;
            bits = 32;
        } else {
            tree = &tree6;
            afam = AF_INET6;
            bits = 128;
        }
        prefix_t *pref = ascii2prefix(afam, cp);
        if (pref == NULL) {
            fprintf(stderr, "ERROR: can't parse prefix %s\n", cp);
            exit(1);
        }
        if (index(cp, '/') == NULL) {
            pref->bitlen = bits;
        }
        if (*tree == NULL) {
            *tree = New_Patricia(bits);
        }
        patricia_lookup(*tree, pref);
        Deref_Prefix(pref);
    }
    lookup_pfix4.family = AF_INET;
    lookup_pfix4.bitlen = 32;
    lookup_pfix4.ref_count = 0;

    lookup_pfix6.family = AF_INET6;
    lookup_pfix6.bitlen = 128;
    lookup_pfix6.ref_count = 0;
}

/* Clear state */
void
scramble_wlw_clear() {
    if (tree4) {
        Destroy_Patricia(tree4, NULL);
        tree4 = NULL;
    }
    if (tree6) {
        Destroy_Patricia(tree6, NULL);
        tree6 = NULL;
    }
}


uint32_t
scramble_wlw_v4(uint32_t oldsrc, int pass_bits) {
    struct in_addr sin;
    if (tree4) {
        sin.s_addr = oldsrc;
        if (scramble_wlw_lookup_addr4(&sin))
            return oldsrc; /* whitelisted */
    }
    return _scrambler_ip4(oldsrc, pass_bits);
}

void
scramble_wlw_v6(struct in6_addr *sin6, int pass_bits) {
    if (tree6) {
        if (scramble_wlw_lookup_addr6(sin6))
            return; /* whitelisted */
    }
    _scrambler_ip6(sin6, pass_bits);
}