libsodium: Needed for Dnscrypto-proxy Release 1.3.0
[tomato.git] / release / src / router / rp-l2tp / peer.c
blobecbce5cfeee14edb8b21154ba128896909bf0191
1 /***********************************************************************
3 * peer.c
5 * Manage lists of peers for L2TP
7 * Copyright (C) 2002 by Roaring Penguin Software Inc.
9 * This software may be distributed under the terms of the GNU General
10 * Public License, Version 2, or (at your option) any later version.
12 * LIC: GPL
14 ***********************************************************************/
16 static char const RCSID[] =
17 "$Id: peer.c,v 1.1.48.1 2005/08/08 12:05:25 honor Exp $";
19 #include "l2tp.h"
20 #include <stddef.h>
21 #include <string.h>
23 static hash_table all_peers;
24 static int peer_process_option(EventSelector *es,
25 char const *name,
26 char const *value);
28 static l2tp_peer prototype;
30 static option_handler peer_option_handler = {
31 NULL, "peer", peer_process_option
34 static int port;
36 static int handle_secret_option(EventSelector *es, l2tp_opt_descriptor *desc, char const *value);
37 static int handle_hostname_option(EventSelector *es, l2tp_opt_descriptor *desc, char const *value);
38 static int handle_peername_option(EventSelector *es, l2tp_opt_descriptor *desc, char const *value);
39 static int set_lac_handler(EventSelector *es, l2tp_opt_descriptor *desc, char const *value);
40 static int handle_lac_option(EventSelector *es, l2tp_opt_descriptor *desc, char const *value);
41 static int set_lns_handler(EventSelector *es, l2tp_opt_descriptor *desc, char const *value);
42 static int handle_lns_option(EventSelector *es, l2tp_opt_descriptor *desc, char const *value);
44 /* Peer options */
45 static l2tp_opt_descriptor peer_opts[] = {
46 /* name type addr */
47 { "peer", OPT_TYPE_IPADDR, &prototype.addr.sin_addr.s_addr},
48 { "mask", OPT_TYPE_INT, &prototype.mask_bits},
49 { "secret", OPT_TYPE_CALLFUNC, (void *) handle_secret_option},
50 { "hostname", OPT_TYPE_CALLFUNC, (void *) handle_hostname_option},
51 { "peername", OPT_TYPE_CALLFUNC, (void *) handle_peername_option},
52 { "port", OPT_TYPE_PORT, &port },
53 { "lac-handler", OPT_TYPE_CALLFUNC, (void *) set_lac_handler},
54 { "lac-opts", OPT_TYPE_CALLFUNC, (void *) handle_lac_option},
55 { "lns-handler", OPT_TYPE_CALLFUNC, (void *) set_lns_handler},
56 { "lns-opts", OPT_TYPE_CALLFUNC, (void *) handle_lns_option},
57 { "hide-avps", OPT_TYPE_BOOL, &prototype.hide_avps},
58 { "retain-tunnel", OPT_TYPE_BOOL, &prototype.retain_tunnel},
59 { "persist", OPT_TYPE_BOOL, &prototype.persist},
60 { "holdoff", OPT_TYPE_INT, &prototype.holdoff},
61 { "maxfail", OPT_TYPE_INT, &prototype.maxfail},
62 { "strict-ip-check", OPT_TYPE_BOOL, &prototype.validate_peer_ip},
63 { NULL, OPT_TYPE_BOOL, NULL }
66 static int
67 set_lac_handler(EventSelector *es,
68 l2tp_opt_descriptor *desc,
69 char const *value)
71 l2tp_lac_handler *handler = l2tp_session_find_lac_handler(value);
72 if (!handler) {
73 l2tp_set_errmsg("No LAC handler named '%s'", value);
74 return -1;
76 prototype.lac_ops = handler->call_ops;
77 return 0;
80 static int
81 set_lns_handler(EventSelector *es,
82 l2tp_opt_descriptor *desc,
83 char const *value)
85 l2tp_lns_handler *handler = l2tp_session_find_lns_handler(value);
86 if (!handler) {
87 l2tp_set_errmsg("No LNS handler named '%s'", value);
88 return -1;
90 prototype.lns_ops = handler->call_ops;
91 return 0;
94 /**********************************************************************
95 * %FUNCTION: handle_secret_option
96 * %ARGUMENTS:
97 * es -- event selector
98 * desc -- descriptor
99 * value -- the secret
100 * %RETURNS:
102 * %DESCRIPTION:
103 * Copies secret to prototype
104 ***********************************************************************/
105 static int
106 handle_secret_option(EventSelector *es,
107 l2tp_opt_descriptor *desc,
108 char const *value)
110 strncpy(prototype.secret, value, MAX_SECRET_LEN);
111 prototype.secret[MAX_SECRET_LEN-1] = 0;
112 prototype.secret_len = strlen(prototype.secret);
113 return 0;
116 /**********************************************************************
117 * %FUNCTION: handle_hostname_option
118 * %ARGUMENTS:
119 * es -- event selector
120 * desc -- descriptor
121 * value -- the hostname
122 * %RETURNS:
124 * %DESCRIPTION:
125 * Copies hostname to prototype
126 ***********************************************************************/
127 static int
128 handle_hostname_option(EventSelector *es,
129 l2tp_opt_descriptor *desc,
130 char const *value)
132 strncpy(prototype.hostname, value, MAX_HOSTNAME);
133 prototype.hostname[MAX_HOSTNAME-1] = 0;
134 prototype.hostname_len = strlen(prototype.hostname);
135 return 0;
138 /**********************************************************************
139 * %FUNCTION: handle_peername_option
140 * %ARGUMENTS:
141 * es -- event selector
142 * desc -- descriptor
143 * value -- the hostname
144 * %RETURNS:
146 * %DESCRIPTION:
147 * Copies peername to prototype
148 ***********************************************************************/
149 static int
150 handle_peername_option(EventSelector *es,
151 l2tp_opt_descriptor *desc,
152 char const *value)
154 strncpy(prototype.peername, value, MAX_HOSTNAME);
155 prototype.peername[MAX_HOSTNAME-1] = 0;
156 prototype.peername_len = strlen(prototype.peername);
157 return 0;
160 /**********************************************************************
161 * %FUNCTION: handle_lac_option
162 * %ARGUMENTS:
163 * es -- event selector
164 * desc -- descriptor
165 * value -- the hostname
166 * %RETURNS:
168 * %DESCRIPTION:
169 * Copies LAC options to prototype
170 ***********************************************************************/
171 static int
172 handle_lac_option(EventSelector *es,
173 l2tp_opt_descriptor *desc,
174 char const *value)
176 char word[512];
177 while (value && *value) {
178 value = l2tp_chomp_word(value, word);
179 if (!word[0]) break;
180 if (prototype.num_lac_options < MAX_OPTS) {
181 char *x = strdup(word);
182 if (x) prototype.lac_options[prototype.num_lac_options++] = x;
183 prototype.lac_options[prototype.num_lac_options] = NULL;
184 } else {
185 break;
188 return 0;
191 /**********************************************************************
192 * %FUNCTION: handle_lns_option
193 * %ARGUMENTS:
194 * es -- event selector
195 * desc -- descriptor
196 * value -- the hostname
197 * %RETURNS:
199 * %DESCRIPTION:
200 * Copies LNS options to prototype
201 ***********************************************************************/
202 static int
203 handle_lns_option(EventSelector *es,
204 l2tp_opt_descriptor *desc,
205 char const *value)
207 char word[512];
208 while (value && *value) {
209 value = l2tp_chomp_word(value, word);
210 if (!word[0]) break;
211 if (prototype.num_lns_options < MAX_OPTS) {
212 char *x = strdup(word);
213 if (x) prototype.lns_options[prototype.num_lns_options++] = x;
214 prototype.lns_options[prototype.num_lns_options] = NULL;
215 } else {
216 break;
219 return 0;
222 /**********************************************************************
223 * %FUNCTION: peer_process_option
224 * %ARGUMENTS:
225 * es -- event selector
226 * name, value -- name and value of option
227 * %RETURNS:
228 * 0 on success, -1 on failure
229 * %DESCRIPTION:
230 * Processes an option in the "peer" section
231 ***********************************************************************/
232 static int
233 peer_process_option(EventSelector *es,
234 char const *name,
235 char const *value)
237 l2tp_peer *peer;
239 /* Special cases: begin and end */
240 if (!strcmp(name, "*begin*")) {
241 /* Switching in to peer context */
242 memset(&prototype, 0, sizeof(prototype));
243 prototype.mask_bits = 32;
244 prototype.validate_peer_ip = 1;
245 port = 1701;
246 return 0;
249 if (!strcmp(name, "*end*")) {
250 /* Validate settings */
251 uint16_t u16 = (uint16_t) port;
252 prototype.addr.sin_port = htons(u16);
253 prototype.addr.sin_family = AF_INET;
255 /* Allow non-authenticated tunnels
256 if (!prototype.secret_len) {
257 l2tp_set_errmsg("No secret supplied for peer");
258 return -1;
261 if (!prototype.lns_ops && !prototype.lac_ops) {
262 l2tp_set_errmsg("You must enable at least one of lns-handler or lac-handler");
263 return -1;
266 /* Add the peer */
267 peer = l2tp_peer_insert(&prototype.addr);
268 if (!peer) return -1;
270 peer->mask_bits = prototype.mask_bits;
271 memcpy(&peer->hostname,&prototype.hostname, sizeof(prototype.hostname));
272 peer->hostname_len = prototype.hostname_len;
273 memcpy(&peer->peername,&prototype.peername, sizeof(prototype.peername));
274 peer->peername_len = prototype.peername_len;
275 memcpy(&peer->secret, &prototype.secret, MAX_SECRET_LEN);
276 peer->secret_len = prototype.secret_len;
277 peer->lns_ops = prototype.lns_ops;
278 memcpy(&peer->lns_options,&prototype.lns_options,sizeof(prototype.lns_options));
279 peer->lac_ops = prototype.lac_ops;
280 memcpy(&peer->lac_options,&prototype.lac_options,sizeof(prototype.lac_options));
281 peer->hide_avps = prototype.hide_avps;
282 peer->retain_tunnel = prototype.retain_tunnel;
283 peer->persist = prototype.persist;
284 peer->holdoff = prototype.holdoff;
285 peer->maxfail = prototype.maxfail;
286 peer->fail = 0;
287 peer->validate_peer_ip = prototype.validate_peer_ip;
288 return 0;
291 /* Process option */
292 return l2tp_option_set(es, name, value, peer_opts);
295 /**********************************************************************
296 * %FUNCTION: peer_compute_hash
297 * %ARGUMENTS:
298 * data -- a void pointer which is really a peer
299 * %RETURNS:
300 * Inet address
301 ***********************************************************************/
302 static unsigned int
303 peer_compute_hash(void *data)
305 unsigned int hash = (unsigned int) (((l2tp_peer *) data)->addr.sin_addr.s_addr);
306 return hash;
309 /**********************************************************************
310 * %FUNCTION: peer_compare
311 * %ARGUMENTS:
312 * item1 -- first peer
313 * item2 -- second peer
314 * %RETURNS:
315 * 0 if both peers have same ID, non-zero otherwise
316 ***********************************************************************/
317 static int
318 peer_compare(void *item1, void *item2)
320 return ((l2tp_peer *) item1)->addr.sin_addr.s_addr !=
321 ((l2tp_peer *) item2)->addr.sin_addr.s_addr;
324 /**********************************************************************
325 * %FUNCTION: peer_init
326 * %ARGUMENTS:
327 * None
328 * %RETURNS:
329 * Nothing
330 * %DESCRIPTION:
331 * Initializes peer hash table
332 ***********************************************************************/
333 void
334 l2tp_peer_init(void)
336 hash_init(&all_peers,
337 offsetof(l2tp_peer, hash),
338 peer_compute_hash,
339 peer_compare);
340 l2tp_option_register_section(&peer_option_handler);
343 /**********************************************************************
344 * %FUNCTION: peer_find
345 * %ARGUMENTS:
346 * addr -- IP address of peer
347 * hostname -- AVP peer hostname
348 * %RETURNS:
349 * A pointer to the peer with given IP address, or NULL if not found.
350 * %DESCRIPTION:
351 * Searches peer hash table for specified peer.
352 ***********************************************************************/
353 l2tp_peer *
354 l2tp_peer_find(struct sockaddr_in *addr, char const *peername)
356 void *cursor;
357 l2tp_peer *peer = NULL;
358 l2tp_peer *candidate = NULL;
359 char addr1_str[16], addr2_str[16];
361 for (candidate = hash_start(&all_peers, &cursor);
362 candidate ;
363 candidate = hash_next(&all_peers, &cursor)) {
365 unsigned long mask = candidate->mask_bits ?
366 htonl(0xFFFFFFFFUL << (32 - candidate->mask_bits)) : 0;
368 strcpy(addr1_str, inet_ntoa(addr->sin_addr));
369 strcpy(addr2_str, inet_ntoa(candidate->addr.sin_addr));
370 DBG(l2tp_db(DBG_TUNNEL, "l2tp_peer_find(%s) examining peer %s/%d\n",
371 addr1_str, addr2_str,
372 candidate->mask_bits));
374 if ((candidate->addr.sin_addr.s_addr & mask) ==
375 (addr->sin_addr.s_addr & mask)
376 && (!peername ||
377 !(candidate->peername[0]) ||
378 !strcmp(peername,candidate->peername))) {
380 if (peer == NULL) {
381 peer = candidate;
382 } else {
383 if (peer->mask_bits < candidate->mask_bits)
384 peer = candidate;
389 strcpy(addr1_str, inet_ntoa(addr->sin_addr));
390 if (peer != NULL)
391 strcpy(addr2_str, inet_ntoa(peer->addr.sin_addr));
392 DBG(l2tp_db(DBG_TUNNEL, "l2tp_peer_find(%s) found %s/%d\n",
393 addr1_str,
394 peer == NULL ? "NULL" : addr2_str,
395 peer == NULL ? -1 : peer->mask_bits));
397 return peer;
400 /**********************************************************************
401 * %FUNCTION: peer_insert
402 * %ARGUMENTS:
403 * addr -- IP address of peer
404 * %RETURNS:
405 * NULL if insert failed, pointer to new peer structure otherwise
406 * %DESCRIPTION:
407 * Inserts a new peer in the all_peers table
408 ***********************************************************************/
409 l2tp_peer *
410 l2tp_peer_insert(struct sockaddr_in *addr)
412 l2tp_peer *peer = malloc(sizeof(l2tp_peer));
413 if (!peer) {
414 l2tp_set_errmsg("peer_insert: Out of memory");
415 return NULL;
417 memset(peer, 0, sizeof(*peer));
419 peer->addr = *addr;
420 hash_insert(&all_peers, peer);
421 return peer;