summaryrefslogtreecommitdiff
path: root/accel-pppd/iprange.c
blob: 6ea2c2f9c856b8abc6a577ca07f54ad17413f664 (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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>

#include "triton.h"
#include "list.h"
#include "log.h"

#include "iprange.h"

#include "memdebug.h"

struct iprange_t
{
	struct list_head entry;
	uint32_t begin;
	uint32_t end;
};

static int conf_disable = 0;

static LIST_HEAD(client_ranges);
//static LIST_HEAD(tunnel_ranges);

//parses ranges like x.x.x.x/mask
static struct iprange_t *parse1(const char *str)
{
	int n,f1,f2,f3,f4,m;
	struct iprange_t *r;
	int mask;

	n = sscanf(str, "%u.%u.%u.%u/%u",&f1, &f2, &f3, &f4, &m);
	if (n != 5)
		return NULL;
	if (f1 > 255)
		return NULL;
	if (f2 > 255)
		return NULL;
	if (f3 > 255)
		return NULL;
	if (f4 > 255)
		return NULL;
	if (m > 32)
		return NULL;

	r = _malloc(sizeof(*r));
	r->begin = (f4 << 24) | (f3 << 16) | (f2 << 8) | f1;

	mask = htonl(~((1 << (32 - m)) - 1));
	r->end = ntohl(r->begin | ~mask);
	r->begin = ntohl(r->begin);

	return r;
}

//parses ranges like x.x.x.x-y
static struct iprange_t *parse2(const char *str)
{
	int n,f1,f2,f3,f4,m;
	struct iprange_t *r;

	n = sscanf(str, "%u.%u.%u.%u-%u",&f1, &f2, &f3, &f4, &m);
	if (n != 5)
		return NULL;
	if (f1 > 255)
		return NULL;
	if (f2 > 255)
		return NULL;
	if (f3 > 255)
		return NULL;
	if (f4 > 255)
		return NULL;
	if (m < f4 || m > 255)
		return NULL;

	r = _malloc(sizeof(*r));
	r->begin = ntohl((f4 << 24) | (f3 << 16) | (f2 << 8) | f1);
	r->end = ntohl((m << 24) | (f3 << 16) | (f2 << 8) | f1);

	return r;
}

static void load_ranges(struct list_head *list, const char *conf_sect)
{
	struct conf_sect_t *s =	conf_get_section(conf_sect);
	struct conf_option_t *opt;
	struct iprange_t *r;

	if (!s) {
		log_emerg("iprange: section '%s' not found in config file, pptp and l2tp probably will not work...\n", conf_sect);
		return;
	}

	list_for_each_entry(opt, &s->items, entry) {
		if (!strcmp(opt->name, "disable"))
			goto disable;
		r = parse1(opt->name);
		if (!r)
			r = parse2(opt->name);
		if (!r) {
			log_emerg("iprange: cann't parse '%s' in '%s'\n", opt->name, conf_sect);
			_exit(EXIT_FAILURE);
		}
		if (r->begin == r->end)
			goto disable;
		list_add_tail(&r->entry, list);
	}

	return;
disable:
	conf_disable = 1;
	log_emerg("iprange: iprange module disabled so improper ip address assigning may cause kernel soft lockup!\n");
}

static int check_range(struct list_head *list, in_addr_t ipaddr)
{
	struct iprange_t *r;
	uint32_t a = ntohl(ipaddr);

	list_for_each_entry(r, list, entry) {
		if (a >= r->begin && a <= r->end)
			return 0;
	}

	return -1;
}

int __export iprange_client_check(in_addr_t ipaddr)
{
	if (conf_disable)
		return 0;

	return check_range(&client_ranges, ipaddr);
}
int __export iprange_tunnel_check(in_addr_t ipaddr)
{
	if (conf_disable)
		return 0;

	return !check_range(&client_ranges, ipaddr);
}

static void iprange_init(void)
{
	load_ranges(&client_ranges, "client-ip-range");
	//load_ranges(&tunnel_ranges, "tunnel-ip-range");
}

DEFINE_INIT(10, iprange_init);