Codebase list l2tpns / 62172ed
Import Debian changes 2.1.19-1 l2tpns (2.1.19-1) unstable; urgency=low * New upstream release. * Add debian/watch file. * Bump Standards-Version to 3.7.2.0 (no changes). Jonathan McDowell authored 17 years ago Sebastien Badia committed 4 years ago
16 changed file(s) with 488 addition(s) and 135 deletion(s). Raw diff Collapse all Expand all
0 * Fri Jun 23 2006 Brendan O'Dea <bod@optus.net> 2.1.19
1 - Kludge around problem with Netgear DM602 authentication.
2 - Use result code AVP to set Acct-Terminate-Cause is disconnect cause
3 AVP is not present.
4
5 * Tue Apr 18 2006 Brendan O'Dea <bod@optus.net> 2.1.18
6 - Don't shutdown on TerminateReq, wait for CDN.
7 - Interpret "local" direction correctly (as LAC) in disconnect AVPs.
8
9 * Thu Apr 13 2006 Brendan O'Dea <bod@optus.net> 2.1.17
10 - Fix IPCP length test to allow Terminate-Request (4 bytes).
11 - Send nsctl responses back using the correct source address (thanks ltd).
12 - Similarly set the source for DAE responses; use bind_address when
13 handling forwarded packets on the master.
14 - Add Acct-Terminate-Cause to RADIUS stop records.
15
016 * Thu Feb 23 2006 Brendan O'Dea <bod@optus.net> 2.1.16
117 - Send configured magic-no in LCP EchoReq when LCP is opened.
218 - Correct addition of single IP to pool (Jonathan Yarden).
2424 Jon Morby <jon@fido.net>
2525 Paul Martin <pm@zetnet.net>
2626 Jonathan Yarden <jyarden@bluegrass.net>
27 Patrick Cole <z@amused.net>
00 // L2TPNS Command Line Interface
11 // vim: sw=8 ts=8
22
3 char const *cvs_name = "$Name: release_2_1_16 $";
3 char const *cvs_name = "$Name: release_2_1_19 $";
44 char const *cvs_id_cli = "$Id: cli.c,v 1.71 2005/12/06 09:43:42 bodea Exp $";
55
66 #include <stdio.h>
00 // L2TPNS Clustering Stuff
11
2 char const *cvs_id_cluster = "$Id: cluster.c,v 1.49 2005/12/05 14:10:42 bodea Exp $";
2 char const *cvs_id_cluster = "$Id: cluster.c,v 1.50 2006/04/05 02:13:48 bodea Exp $";
33
44 #include <stdio.h>
55 #include <stdlib.h>
16541654
16551655 STAT(recv_forward);
16561656 if (type == C_FORWARD_DAE)
1657 processdae(p, s, &a, sizeof(a));
1657 {
1658 struct in_addr local;
1659 local.s_addr = config->bind_address ? config->bind_address : my_address;
1660 processdae(p, s, &a, sizeof(a), &local);
1661 }
16581662 else
16591663 processudp(p, s, &a);
16601664
0 l2tpns (2.1.19-1) unstable; urgency=low
1
2 * New upstream release.
3 * Add debian/watch file.
4 * Bump Standards-Version to 3.7.2.0 (no changes).
5
6 -- Jonathan McDowell <noodles@earth.li> Sat, 22 Jul 2006 14:11:14 +0100
7
08 l2tpns (2.1.16-1) unstable; urgency=low
19
210 * New upstream release.
22 Priority: optional
33 Maintainer: Jonathan McDowell <noodles@earth.li>
44 Build-Depends: debhelper (>> 4), libcli-dev (>> 1.8.5)
5 Standards-Version: 3.6.2.0
5 Standards-Version: 3.7.2.0
66
77 Package: l2tpns
88 Architecture: any
0 # format version number, currently 3; this line is compulsory!
1 version=3
2
3 http://sf.net/l2tpns/l2tpns-(.*)\.tar\.gz
33 // Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced
44 // vim: sw=8 ts=8
55
6 char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.156 2006/02/17 13:27:07 bodea Exp $";
6 char const *cvs_id_l2tpns = "$Id: l2tpns.c,v 1.161.2.1 2006/06/22 15:30:50 bodea Exp $";
77
88 #include <arpa/inet.h>
99 #include <assert.h>
199199 static int add_plugin(char *plugin_name);
200200 static int remove_plugin(char *plugin_name);
201201 static void plugins_done(void);
202 static void processcontrol(uint8_t *buf, int len, struct sockaddr_in *addr, int alen);
202 static void processcontrol(uint8_t *buf, int len, struct sockaddr_in *addr, int alen, struct in_addr *local);
203203 static tunnelidt new_tunnel(void);
204204 static void unhide_value(uint8_t *value, size_t len, uint16_t type, uint8_t *vector, size_t vec_len);
205205
633633 addr.sin_port = htons(NSCTL_PORT);
634634 controlfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
635635 setsockopt(controlfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
636 setsockopt(controlfd, SOL_IP, IP_PKTINFO, &on, sizeof(on)); // recvfromto
636637 if (bind(controlfd, (void *) &addr, sizeof(addr)) < 0)
637638 {
638639 LOG(0, 0, 0, "Error in control bind: %s\n", strerror(errno));
645646 addr.sin_port = htons(config->radius_dae_port);
646647 daefd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
647648 setsockopt(daefd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
649 setsockopt(daefd, SOL_IP, IP_PKTINFO, &on, sizeof(on)); // recvfromto
648650 if (bind(daefd, (void *) &addr, sizeof(addr)) < 0)
649651 {
650652 LOG(0, 0, 0, "Error in DAE bind: %s\n", strerror(errno));
15561558 }
15571559
15581560 // start tidy shutdown of session
1559 void sessionshutdown(sessionidt s, char *reason, int result, int error)
1561 void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_error, int term_cause)
15601562 {
15611563 int walled_garden = session[s].walled_garden;
15621564
15841586 {
15851587 // stop, if not already trying
15861588 if (radius[r].state != RADIUSSTOP)
1589 {
1590 radius[r].term_cause = term_cause;
1591 radius[r].term_msg = reason;
15871592 radiussend(r, RADIUSSTOP);
1593 }
15881594 }
15891595 else
15901596 LOG(1, s, session[s].tunnel, "No free RADIUS sessions for Stop message\n");
16241630 if (session[s].throttle_in || session[s].throttle_out) // Unthrottle if throttled.
16251631 throttle_session(s, 0, 0);
16261632
1627 if (result)
1633 if (cdn_result)
16281634 { // Send CDN
16291635 controlt *c = controlnew(14); // sending CDN
1630 if (error)
1636 if (cdn_error)
16311637 {
16321638 uint8_t buf[4];
1633 *(uint16_t *) buf = htons(result);
1634 *(uint16_t *) (buf+2) = htons(error);
1639 *(uint16_t *) buf = htons(cdn_result);
1640 *(uint16_t *) (buf+2) = htons(cdn_error);
16351641 controlb(c, 1, buf, 4, 1);
16361642 }
16371643 else
1638 control16(c, 1, result, 1);
1644 control16(c, 1, cdn_result, 1);
16391645
16401646 control16(c, 14, s, 1); // assigned session (our end)
16411647 controladd(c, session[s].far, session[s].tunnel); // send the message
17411747 }
17421748
17431749 session[s].die = TIME;
1744 sessionshutdown(s, reason, 3, 0); // close radius/routes, etc.
1750 sessionshutdown(s, reason, CDN_ADMIN_DISC, TERM_ADMIN_RESET); // close radius/routes, etc.
17451751 if (sess_local[s].radius)
17461752 radiusclear(sess_local[s].radius, s); // cant send clean accounting data, session is killed
17471753
18061812 // close session
18071813 for (s = 1; s <= config->cluster_highest_sessionid ; ++s)
18081814 if (session[s].tunnel == t)
1809 sessionshutdown(s, reason, 0, 0);
1815 sessionshutdown(s, reason, CDN_NONE, TERM_ADMIN_RESET);
18101816
18111817 tunnel[t].state = TUNNELDIE;
18121818 tunnel[t].die = TIME + 700; // Clean up in 70 seconds
20452051 int error = 0;
20462052 char *msg = 0;
20472053
2054 // Default disconnect cause/message on receipt of CDN. Set to
2055 // more specific value from attribute 1 (result code) or 46
2056 // (disconnect cause) if present below.
2057 int disc_cause_set = 0;
2058 int disc_cause = TERM_NAS_REQUEST;
2059 char const *disc_reason = "Closed (Received CDN).";
2060
20482061 // process AVPs
20492062 while (l && !(fatal & 0x80)) // 0x80 = mandatory AVP
20502063 {
20522065 uint8_t *b = p;
20532066 uint8_t flags = *p;
20542067 uint16_t mtype;
2068
20552069 if (n > l)
20562070 {
20572071 LOG(1, s, t, "Invalid length in AVP\n");
21502164 case 1: // result code
21512165 {
21522166 uint16_t rescode = ntohs(*(uint16_t *) b);
2153 const char* resdesc = "(unknown)";
2167 char const *resdesc = "(unknown)";
2168 char const *errdesc = NULL;
2169 int cause = 0;
2170
21542171 if (message == 4)
21552172 { /* StopCCN */
21562173 resdesc = l2tp_stopccn_result_code(rescode);
2174 cause = TERM_LOST_SERVICE;
21572175 }
21582176 else if (message == 14)
21592177 { /* CDN */
21602178 resdesc = l2tp_cdn_result_code(rescode);
2179 if (rescode == 1)
2180 cause = TERM_LOST_CARRIER;
2181 else
2182 cause = TERM_ADMIN_RESET;
21612183 }
21622184
21632185 LOG(4, s, t, " Result Code %d: %s\n", rescode, resdesc);
21642186 if (n >= 4)
21652187 {
21662188 uint16_t errcode = ntohs(*(uint16_t *)(b + 2));
2167 LOG(4, s, t, " Error Code %d: %s\n", errcode, l2tp_error_code(errcode));
2189 errdesc = l2tp_error_code(errcode);
2190 LOG(4, s, t, " Error Code %d: %s\n", errcode, errdesc);
21682191 }
21692192 if (n > 4)
21702193 LOG(4, s, t, " Error String: %.*s\n", n-4, b+4);
2194
2195 if (cause && disc_cause_set < mtype) // take cause from attrib 46 in preference
2196 {
2197 disc_cause_set = mtype;
2198 disc_reason = errdesc ? errdesc : resdesc;
2199 disc_cause = cause;
2200 }
21712201
21722202 break;
21732203 }
21882218 }
21892219 break;
21902220 case 3: // framing capabilities
2191 // LOG(4, s, t, "Framing capabilities\n");
21922221 break;
21932222 case 4: // bearer capabilities
2194 // LOG(4, s, t, "Bearer capabilities\n");
21952223 break;
21962224 case 5: // tie breaker
21972225 // We never open tunnels, so we don't care about tie breakers
2198 // LOG(4, s, t, "Tie breaker\n");
21992226 continue;
22002227 case 6: // firmware revision
2201 // LOG(4, s, t, "Firmware revision\n");
22022228 break;
22032229 case 7: // host name
22042230 memset(tunnel[t].hostname, 0, sizeof(tunnel[t].hostname));
23532379 memcpy(session[s].random_vector, b, n);
23542380 session[s].random_vector_length = n;
23552381 break;
2382 case 46: // ppp disconnect cause
2383 if (n >= 5)
2384 {
2385 uint16_t code = ntohs(*(uint16_t *) b);
2386 uint16_t proto = ntohs(*(uint16_t *) (b + 2));
2387 uint8_t dir = *(b + 4);
2388
2389 LOG(4, s, t, " PPP disconnect cause "
2390 "(code=%u, proto=%04X, dir=%u, msg=\"%.*s\")\n",
2391 code, proto, dir, n - 5, b + 5);
2392
2393 disc_cause_set = mtype;
2394
2395 switch (code)
2396 {
2397 case 1: // admin disconnect
2398 disc_cause = TERM_ADMIN_RESET;
2399 disc_reason = "Administrative disconnect";
2400 break;
2401 case 3: // lcp terminate
2402 if (dir != 2) break; // 1=peer (LNS), 2=local (LAC)
2403 disc_cause = TERM_USER_REQUEST;
2404 disc_reason = "Normal disconnection";
2405 break;
2406 case 4: // compulsory encryption unavailable
2407 if (dir != 1) break; // 1=refused by peer, 2=local
2408 disc_cause = TERM_USER_ERROR;
2409 disc_reason = "Compulsory encryption refused";
2410 break;
2411 case 5: // lcp: fsm timeout
2412 disc_cause = TERM_PORT_ERROR;
2413 disc_reason = "LCP: FSM timeout";
2414 break;
2415 case 6: // lcp: no recognisable lcp packets received
2416 disc_cause = TERM_PORT_ERROR;
2417 disc_reason = "LCP: no recognisable LCP packets";
2418 break;
2419 case 7: // lcp: magic-no error (possibly looped back)
2420 disc_cause = TERM_PORT_ERROR;
2421 disc_reason = "LCP: magic-no error (possible loop)";
2422 break;
2423 case 8: // lcp: echo request timeout
2424 disc_cause = TERM_PORT_ERROR;
2425 disc_reason = "LCP: echo request timeout";
2426 break;
2427 case 13: // auth: fsm timeout
2428 disc_cause = TERM_SERVICE_UNAVAILABLE;
2429 disc_reason = "Authentication: FSM timeout";
2430 break;
2431 case 15: // auth: unacceptable auth protocol
2432 disc_cause = TERM_SERVICE_UNAVAILABLE;
2433 disc_reason = "Unacceptable authentication protocol";
2434 break;
2435 case 16: // auth: authentication failed
2436 disc_cause = TERM_SERVICE_UNAVAILABLE;
2437 disc_reason = "Authentication failed";
2438 break;
2439 case 17: // ncp: fsm timeout
2440 disc_cause = TERM_SERVICE_UNAVAILABLE;
2441 disc_reason = "NCP: FSM timeout";
2442 break;
2443 case 18: // ncp: no ncps available
2444 disc_cause = TERM_SERVICE_UNAVAILABLE;
2445 disc_reason = "NCP: no NCPs available";
2446 break;
2447 case 19: // ncp: failure to converge on acceptable address
2448 disc_cause = TERM_SERVICE_UNAVAILABLE;
2449 disc_reason = (dir == 1)
2450 ? "NCP: too many Configure-Naks received from peer"
2451 : "NCP: too many Configure-Naks sent to peer";
2452 break;
2453 case 20: // ncp: user not permitted to use any address
2454 disc_cause = TERM_SERVICE_UNAVAILABLE;
2455 disc_reason = (dir == 1)
2456 ? "NCP: local link address not acceptable to peer"
2457 : "NCP: remote link address not acceptable";
2458 break;
2459 }
2460 }
2461 break;
23562462 default:
23572463 {
23582464 static char e[] = "unknown AVP 0xXXXX";
24742580
24752581 case 14: // CDN
24762582 controlnull(t); // ack
2477 sessionshutdown(s, "Closed (Received CDN).", 0, 0);
2583 sessionshutdown(s, disc_reason, CDN_NONE, disc_cause);
24782584 break;
24792585 case 0xFFFF:
24802586 LOG(1, s, t, "Missing message type\n");
28042910 }
28052911 else
28062912 {
2807 sessionshutdown(s, "No response to LCP ConfigReq.", 3, 0);
2913 sessionshutdown(s, "No response to LCP ConfigReq.", CDN_ADMIN_DISC, TERM_LOST_SERVICE);
28082914 STAT(session_timeout);
28092915 }
28102916
28332939 }
28342940 else
28352941 {
2836 sessionshutdown(s, "No response to IPCP ConfigReq.", 3, 0);
2942 sessionshutdown(s, "No response to IPCP ConfigReq.", CDN_ADMIN_DISC, TERM_LOST_SERVICE);
28372943 STAT(session_timeout);
28382944 }
28392945
28993005 // Drop sessions who have not responded within IDLE_TIMEOUT seconds
29003006 if (session[s].last_packet && (time_now - session[s].last_packet >= IDLE_TIMEOUT))
29013007 {
2902 sessionshutdown(s, "No response to LCP ECHO requests.", 3, 0);
3008 sessionshutdown(s, "No response to LCP ECHO requests.", CDN_ADMIN_DISC, TERM_LOST_SERVICE);
29033009 STAT(session_timeout);
29043010 s_actions++;
29053011 continue;
29353041 if (a & CLI_SESS_KILL)
29363042 {
29373043 LOG(2, s, session[s].tunnel, "Dropping session by CLI\n");
2938 sessionshutdown(s, "Requested by administrator.", 3, 0);
3044 sessionshutdown(s, "Requested by administrator.", CDN_ADMIN_DISC, TERM_ADMIN_RESET);
29393045 a = 0; // dead, no need to check for other actions
29403046 s_actions++;
29413047 }
32473353 if (n)
32483354 {
32493355 struct sockaddr_in addr;
3356 struct in_addr local;
32503357 socklen_t alen;
32513358 int c, s;
32523359 int udp_ready = 0;
32633370 for (c = n, i = 0; i < c; i++)
32643371 {
32653372 struct event_data *d = events[i].data.ptr;
3373
32663374 switch (d->type)
32673375 {
32683376 case FD_TYPE_CLI: // CLI connections
32893397
32903398 case FD_TYPE_CONTROL: // nsctl commands
32913399 alen = sizeof(addr);
3292 processcontrol(buf, recvfrom(controlfd, buf, sizeof(buf), MSG_WAITALL, (void *) &addr, &alen), &addr, alen);
3400 s = recvfromto(controlfd, buf, sizeof(buf), MSG_WAITALL, (struct sockaddr *) &addr, &alen, &local);
3401 if (s > 0) processcontrol(buf, s, &addr, alen, &local);
32933402 n--;
32943403 break;
32953404
32963405 case FD_TYPE_DAE: // DAE requests
32973406 alen = sizeof(addr);
3298 processdae(buf, recvfrom(daefd, buf, sizeof(buf), MSG_WAITALL, (void *) &addr, &alen), &addr, alen);
3407 s = recvfromto(daefd, buf, sizeof(buf), MSG_WAITALL, (struct sockaddr *) &addr, &alen, &local);
3408 if (s > 0) processdae(buf, s, &addr, alen, &local);
32993409 n--;
33003410 break;
33013411
33023412 case FD_TYPE_RADIUS: // RADIUS response
33033413 alen = sizeof(addr);
3304 s = recvfrom(radfds[d->index], buf, sizeof(buf), MSG_WAITALL, (void *) &addr, &alen);
3414 s = recvfrom(radfds[d->index], buf, sizeof(buf), MSG_WAITALL, (struct sockaddr *) &addr, &alen);
33053415 if (s >= 0 && config->cluster_iam_master)
33063416 {
33073417 if (addr.sin_addr.s_addr == config->radiusserver[0] ||
44954605 if (!session[s].ip)
44964606 {
44974607 LOG(0, s, t, " No IP allocated. The IP address pool is FULL!\n");
4498 sessionshutdown(s, "No IP addresses available.", 2, 7); // try another
4608 sessionshutdown(s, "No IP addresses available.", CDN_TRY_ANOTHER, TERM_SERVICE_UNAVAILABLE);
44994609 return 0;
45004610 }
45014611 LOG(3, s, t, " No IP allocated. Assigned %s from pool\n",
48824992 run_plugin_done(p);
48834993 }
48844994
4885 static void processcontrol(uint8_t *buf, int len, struct sockaddr_in *addr, int alen)
4995 static void processcontrol(uint8_t *buf, int len, struct sockaddr_in *addr, int alen, struct in_addr *local)
48864996 {
48874997 struct nsctl request;
48884998 struct nsctl response;
50405150 r = pack_control(buf, NSCTL_MAX_PKT_SZ, response.type, response.argc, response.argv);
50415151 if (r > 0)
50425152 {
5043 sendto(controlfd, buf, r, 0, (const struct sockaddr *) addr, alen);
5153 sendtofrom(controlfd, buf, r, 0, (const struct sockaddr *) addr, alen, local);
50445154 if (log_stream && config->debug >= 4)
50455155 {
50465156 LOG(4, 0, 0, "Sent [%s] ", fmtaddr(addr->sin_addr.s_addr, 0));
00 // L2TPNS Global Stuff
1 // $Id: l2tpns.h,v 1.109 2005/12/20 04:57:16 bodea Exp $
1 // $Id: l2tpns.h,v 1.113.2.1 2006/05/26 07:33:52 bodea Exp $
22
33 #ifndef __L2TPNS_H__
44 #define __L2TPNS_H__
1313 #include <sys/types.h>
1414 #include <libcli.h>
1515
16 #define VERSION "2.1.16"
16 #define VERSION "2.1.19"
1717
1818 // Limits
1919 #define MAXTUNNEL 500 // could be up to 65535
146146
147147 // reset state machine counters
148148 #define initialise_restart_count(_s, _fsm) \
149 sess_local[_s]._fsm.conf_sent = sess_local[_s]._fsm.nak_sent = 0
149 sess_local[_s]._fsm.conf_sent = \
150 sess_local[_s]._fsm.nak_sent = 0
151
152 // no more attempts
153 #define zero_restart_count(_s, _fsm) ({ \
154 sess_local[_s]._fsm.conf_sent = \
155 config->ppp_max_configure; \
156 sess_local[_s]._fsm.restart = \
157 time_now + config->ppp_restart_time; \
158 })
150159
151160 // increment ConfReq counter and reset timer
152161 #define restart_timer(_s, _fsm) ({ \
344353 }
345354 tunnelt;
346355
347 // 160 bytes per radius session
356 // 164 bytes per radius session
348357 typedef struct // outstanding RADIUS requests
349358 {
350359 sessionidt session; // which session this applies to
355364 uint8_t try; // which try we are on
356365 uint8_t state; // state of radius requests
357366 uint8_t chap; // set if CHAP used (is CHAP identifier)
367 uint8_t term_cause; // Stop record: Acct-Terminate-Cause
368 char const *term_msg; // terminate reason
358369 }
359370 radiust;
360371
673684 int used; // session ref count
674685 } ip_filtert;
675686
687 // CDN result/error codes
688 #define CDN_NONE 0, 0
689 #define CDN_TRY_ANOTHER 2, 7
690 #define CDN_ADMIN_DISC 3, 0
691 #define CDN_UNAVAILABLE 4, 0
692
693 // RADIUS Acct-Terminate-Cause values
694 #define TERM_USER_REQUEST 1
695 #define TERM_LOST_CARRIER 2
696 #define TERM_LOST_SERVICE 3
697 #define TERM_IDLE_TIMEOUT 4
698 #define TERM_SESSION_TIMEOUT 5
699 #define TERM_ADMIN_RESET 6
700 #define TERM_ADMIN_REBOOT 7
701 #define TERM_PORT_ERROR 8
702 #define TERM_NAS_ERROR 9
703 #define TERM_NAS_REQUEST 10
704 #define TERM_NAS_REBOOT 11
705 #define TERM_PORT_UNNEEDED 12
706 #define TERM_PORT_PREEMPTED 13
707 #define TERM_PORT_SUSPENDED 14
708 #define TERM_SERVICE_UNAVAILABLE 15
709 #define TERM_CALLBACK 16
710 #define TERM_USER_ERROR 17
711 #define TERM_HOST_REQUEST 18
712 #define TERM_SUPPLICANT_RESTART 19
713 #define TERM_REAUTHENTICATION_FAILURE 20
714 #define TERM_PORT_REINIT 21
715 #define TERM_PORT_DISABLED 22
716
676717 // arp.c
677718 void sendarp(int ifr_idx, const unsigned char* mac, in_addr_t ip);
678719
702743 void radiusretry(uint16_t r);
703744 uint16_t radiusnew(sessionidt s);
704745 void radiusclear(uint16_t r, sessionidt s);
705 void processdae(uint8_t *buf, int len, struct sockaddr_in *addr, int alen);
746 void processdae(uint8_t *buf, int len, struct sockaddr_in *addr, int alen, struct in_addr *local);
706747
707748
708749 // l2tpns.c
715756 void increment_counter(uint32_t *counter, uint32_t *wrap, uint32_t delta);
716757 void random_data(uint8_t *buf, int len);
717758 void sessionkill(sessionidt s, char *reason);
718 void sessionshutdown(sessionidt s, char *reason, int result, int error);
759 void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_error, int term_cause);
719760 void filter_session(sessionidt s, int filter_in, int filter_out);
720761 void send_garp(in_addr_t ip);
721762 void tunnelsend(uint8_t *buf, uint16_t l, tunnelidt t);
00 Summary: A high-speed clustered L2TP LNS
11 Name: l2tpns
2 Version: 2.1.16
2 Version: 2.1.19
33 Release: 1
44 License: GPL
55 Group: System Environment/Daemons
4242 %attr(644,root,root) /usr/share/man/man[58]/*
4343
4444 %changelog
45 * Thu Feb 23 2006 Brendan O'Dea <bod@optus.net> 2.1.16-1
46 - 2.1.16 release, see /usr/share/doc/l2tpns-2.1.16/Changes
45 * Fri Jun 23 2006 Brendan O'Dea <bod@optus.net> 2.1.19-1
46 - 2.1.19 release, see /usr/share/doc/l2tpns-2.1.19/Changes
00 #ifndef __PLUGIN_H__
11 #define __PLUGIN_H__
22
3 #define PLUGIN_API_VERSION 6
3 #define PLUGIN_API_VERSION 7
44 #define MAX_PLUGIN_TYPES 30
55
66 enum
3636 uint16_t (*radiusnew)(sessionidt s);
3737 void (*radiussend)(uint16_t r, uint8_t state);
3838 void *(*getconfig)(char *key, enum config_typet type);
39 void (*sessionshutdown)(sessionidt s, char *reason, int result, int error);
39 void (*sessionshutdown)(sessionidt s, char const *reason, int result, int error, int term_cause);
4040 void (*sessionkill)(sessionidt s, char *reason);
4141 void (*throttle)(sessionidt s, int rate_in, int rate_out);
4242 int (*session_changed)(int sid);
+102
-35
ppp.c less more
00 // L2TPNS PPP Stuff
11
2 char const *cvs_id_ppp = "$Id: ppp.c,v 1.96 2006/02/17 15:05:14 bodea Exp $";
2 char const *cvs_id_ppp = "$Id: ppp.c,v 1.99.2.1 2006/05/26 07:33:52 bodea Exp $";
33
44 #include <stdio.h>
55 #include <string.h>
3939 {
4040 LOG(1, s, t, "Short PAP %u bytes\n", l);
4141 STAT(tunnel_rx_errors);
42 sessionshutdown(s, "Short PAP packet.", 3, 0);
42 sessionshutdown(s, "Short PAP packet.", CDN_ADMIN_DISC, TERM_USER_ERROR);
4343 return;
4444 }
4545
4747 {
4848 LOG(1, s, t, "Length mismatch PAP %u/%u\n", hl, l);
4949 STAT(tunnel_rx_errors);
50 sessionshutdown(s, "PAP length mismatch.", 3, 0);
50 sessionshutdown(s, "PAP length mismatch.", CDN_ADMIN_DISC, TERM_USER_ERROR);
5151 return;
5252 }
5353 l = hl;
5656 {
5757 LOG(1, s, t, "Unexpected PAP code %d\n", *p);
5858 STAT(tunnel_rx_errors);
59 sessionshutdown(s, "Unexpected PAP code.", 3, 0);
59 sessionshutdown(s, "Unexpected PAP code.", CDN_ADMIN_DISC, TERM_USER_ERROR);
6060 return;
6161 }
6262
109109 else
110110 {
111111 LOG(1, s, t, "No RADIUS session available to authenticate session...\n");
112 sessionshutdown(s, "No free RADIUS sessions.", 4, 0);
112 sessionshutdown(s, "No free RADIUS sessions.", CDN_UNAVAILABLE, TERM_SERVICE_UNAVAILABLE);
113113 }
114114 }
115115 else
151151 {
152152 LOG(1, s, t, "Short CHAP %u bytes\n", l);
153153 STAT(tunnel_rx_errors);
154 sessionshutdown(s, "Short CHAP packet.", 3, 0);
154 sessionshutdown(s, "Short CHAP packet.", CDN_ADMIN_DISC, TERM_USER_ERROR);
155155 return;
156156 }
157157
159159 {
160160 LOG(1, s, t, "Length mismatch CHAP %u/%u\n", hl, l);
161161 STAT(tunnel_rx_errors);
162 sessionshutdown(s, "CHAP length mismatch.", 3, 0);
162 sessionshutdown(s, "CHAP length mismatch.", CDN_ADMIN_DISC, TERM_USER_ERROR);
163163 return;
164164 }
165165 l = hl;
168168 {
169169 LOG(1, s, t, "Unexpected CHAP response code %d\n", *p);
170170 STAT(tunnel_rx_errors);
171 sessionshutdown(s, "CHAP length mismatch.", 3, 0);
171 sessionshutdown(s, "CHAP length mismatch.", CDN_ADMIN_DISC, TERM_USER_ERROR);
172 return;
173 }
174
175 if (session[s].ppp.phase != Authenticate)
176 {
177 LOG(2, s, t, "CHAP ignored in %s phase\n", ppp_phase(session[s].ppp.phase));
172178 return;
173179 }
174180
176182 if (!r)
177183 {
178184 LOG(3, s, t, "Unexpected CHAP message\n");
179 return;
180 }
181
182 if (session[s].ppp.phase != Authenticate)
183 {
184 LOG(2, s, t, "CHAP ignored in %s phase\n", ppp_phase(session[s].ppp.phase));
185
186 // Some modems (Netgear DM602, possibly others) persist in using CHAP even
187 // after ACKing our ConfigReq for PAP.
188 if (sess_local[s].lcp_authtype == AUTHPAP && config->radius_authtypes & AUTHCHAP)
189 {
190 sess_local[s].lcp_authtype = AUTHCHAP;
191 sendchap(s, t);
192 }
185193 return;
186194 }
187195
189197 {
190198 LOG(1, s, t, "Wrong CHAP response ID %d (should be %d) (%d)\n", p[1], radius[r].id, r);
191199 STAT(tunnel_rx_errors);
192 sessionshutdown(s, "Unexpected CHAP response ID.", 3, 0);
200 sessionshutdown(s, "Unexpected CHAP response ID.", CDN_ADMIN_DISC, TERM_USER_ERROR);
193201 return;
194202 }
195203
197205 {
198206 LOG(1, s, t, "Bad CHAP response length %d\n", l < 5 ? -1 : p[4]);
199207 STAT(tunnel_rx_errors);
200 sessionshutdown(s, "Bad CHAP response length.", 3, 0);
208 sessionshutdown(s, "Bad CHAP response length.", CDN_ADMIN_DISC, TERM_USER_ERROR);
201209 return;
202210 }
203211
207215 {
208216 LOG(1, s, t, "CHAP user too long %d\n", l - 16);
209217 STAT(tunnel_rx_errors);
210 sessionshutdown(s, "CHAP username too long.", 3, 0);
218 sessionshutdown(s, "CHAP username too long.", CDN_ADMIN_DISC, TERM_USER_ERROR);
211219 return;
212220 }
213221
813821
814822 default:
815823 LOG(2, s, t, "LCP: remote sent %s for type %u?\n", ppp_code(*p), type);
816 sessionshutdown(s, "Unable to negotiate LCP.", 3, 0);
824 sessionshutdown(s, "Unable to negotiate LCP.", CDN_ADMIN_DISC, TERM_USER_ERROR);
817825 return;
818826 }
819827 x -= length;
822830
823831 if (!authtype)
824832 {
825 sessionshutdown(s, "Unsupported authentication.", 3, 0);
833 sessionshutdown(s, "Unsupported authentication.", CDN_ADMIN_DISC, TERM_USER_ERROR);
826834 return;
827835 }
828836
869877 }
870878 else if (*p == TerminateReq)
871879 {
872 *p = TerminateAck; // close
880 switch (session[s].ppp.lcp)
881 {
882 case Closed:
883 case Stopped:
884 case Closing:
885 case Stopping:
886 case RequestSent:
887 case AckReceived:
888 case AckSent:
889 break;
890
891 case Opened:
892 lcp_restart(s);
893 zero_restart_count(s, lcp);
894 change_state(s, lcp, Closing);
895 break;
896
897 default:
898 LOG(2, s, t, "LCP: ignoring %s in state %s\n", ppp_code(*p), ppp_state(session[s].ppp.lcp));
899 return;
900 }
901
902 *p = TerminateAck; // send ack
873903 q = makeppp(b, sizeof(b), p, l, s, t, PPPLCP);
874904 if (!q) return;
875905
877907 if (config->debug > 3) dumplcp(q, l);
878908
879909 tunnelsend(b, l + (q - b), t); // send it
880 sessionshutdown(s, "Remote end closed connection.", 3, 0);
881 }
882 else if (*p == TerminateAck)
883 {
884 sessionshutdown(s, "Connection closed.", 3, 0);
885910 }
886911 else if (*p == ProtocolRej)
887912 {
966991 CSTAT(processipcp);
967992
968993 LOG_HEX(5, "IPCP", p, l);
969 if (l < 5)
994 if (l < 4)
970995 {
971996 LOG(1, s, t, "Short IPCP %d bytes\n", l);
972997 STAT(tunnel_rx_errors);
10381063 q = ppp_conf_nak(s, b, sizeof(b), PPPIPCP, &response, q, p, o, (uint8_t *) &addr, sizeof(addr));
10391064 if (!q || (q != oq && *response == ConfigRej))
10401065 {
1041 sessionshutdown(s, "Can't negotiate IPCP.", 3, 0);
1066 sessionshutdown(s, "Can't negotiate IPCP.", CDN_ADMIN_DISC, TERM_USER_ERROR);
10421067 return;
10431068 }
10441069 }
11521177 }
11531178 else if (*p == TerminateReq)
11541179 {
1155 *p = TerminateAck;
1156 q = makeppp(b, sizeof(b), p, l, s, t, PPPIPCP);
1180 switch (session[s].ppp.ipcp)
1181 {
1182 case Closed:
1183 case Stopped:
1184 case Closing:
1185 case Stopping:
1186 case RequestSent:
1187 case AckReceived:
1188 case AckSent:
1189 break;
1190
1191 case Opened:
1192 zero_restart_count(s, ipcp);
1193 change_state(s, ipcp, Closing);
1194 break;
1195
1196 default:
1197 LOG(2, s, t, "IPCP: ignoring %s in state %s\n", ppp_code(*p), ppp_state(session[s].ppp.ipcp));
1198 return;
1199 }
1200
1201 *p = TerminateAck; // send ack
1202 q = makeppp(b, sizeof(b), p, l, s, t, PPPIPCP);
11571203 if (!q) return;
1204
11581205 LOG(3, s, t, "IPCP: send %s\n", ppp_code(*q));
1159 tunnelsend(b, l + (q - b), t);
1160 change_state(s, ipcp, Stopped);
1206 tunnelsend(b, l + (q - b), t); // send it
11611207 }
11621208 else if (*p != CodeRej)
11631209 {
13521398 }
13531399 else if (*p == TerminateReq)
13541400 {
1355 *p = TerminateAck;
1401 switch (session[s].ppp.ipv6cp)
1402 {
1403 case Closed:
1404 case Stopped:
1405 case Closing:
1406 case Stopping:
1407 case RequestSent:
1408 case AckReceived:
1409 case AckSent:
1410 break;
1411
1412 case Opened:
1413 zero_restart_count(s, ipv6cp);
1414 change_state(s, ipv6cp, Closing);
1415 break;
1416
1417 default:
1418 LOG(2, s, t, "IPV6CP: ignoring %s in state %s\n", ppp_code(*p), ppp_state(session[s].ppp.ipv6cp));
1419 return;
1420 }
1421
1422 *p = TerminateAck; // send ack
13561423 q = makeppp(b, sizeof(b), p, l, s, t, PPPIPV6CP);
13571424 if (!q) return;
1425
13581426 LOG(3, s, t, "IPV6CP: send %s\n", ppp_code(*q));
1359 tunnelsend(b, l + (q - b), t);
1360 change_state(s, ipv6cp, Stopped);
1427 tunnelsend(b, l + (q - b), t); // send it
13611428 }
13621429 else if (*p != CodeRej)
13631430 {
17561823 radius[r].retry = backoff(radius[r].try++);
17571824 if (radius[r].try > 5)
17581825 {
1759 sessionshutdown(s, "CHAP timeout.", 3, 0);
1826 sessionshutdown(s, "CHAP timeout.", CDN_ADMIN_DISC, TERM_REAUTHENTICATION_FAILURE);
17601827 STAT(tunnel_tx_errors);
17611828 return ;
17621829 }
00 // L2TPNS Radius Stuff
11
2 char const *cvs_id_radius = "$Id: radius.c,v 1.47 2005/12/19 06:18:13 bodea Exp $";
2 char const *cvs_id_radius = "$Id: radius.c,v 1.49 2006/04/13 11:14:35 bodea Exp $";
33
44 #include <time.h>
55 #include <stdio.h>
157157 if (s)
158158 {
159159 if (state == RADIUSAUTH)
160 sessionshutdown(s, "RADIUS timeout.", 3, 0);
160 sessionshutdown(s, "RADIUS timeout.", CDN_ADMIN_DISC, TERM_REAUTHENTICATION_FAILURE);
161161 else
162162 {
163163 LOG(1, s, session[s].tunnel, "RADIUS timeout, but in state %s so don't timeout session\n",
247247 p += p[1];
248248 }
249249 }
250 else if (state == RADIUSSTART || state == RADIUSSTOP || state == RADIUSINTERIM)
251 { // accounting
250 else // accounting
251 {
252252 *p = 40; // accounting type
253253 p[1] = 6;
254254 *(uint32_t *) (p + 2) = htonl(state - RADIUSSTART + 1); // start=1, stop=2, interim=3
303303 p[1] = 6;
304304 *(uint32_t *) (p + 2) = htonl(session[s].cout_wrap);
305305 p += p[1];
306
307 if (state == RADIUSSTOP && radius[r].term_cause)
308 {
309 *p = 49; // acct-terminate-cause
310 p[1] = 6;
311 *(uint32_t *) (p + 2) = htonl(radius[r].term_cause);
312 p += p[1];
313
314 if (radius[r].term_msg)
315 {
316 *p = 26; // vendor-specific
317 *(uint32_t *) (p + 2) = htonl(9); // Cisco
318 p[6] = 1; // Cisco-AVPair
319 p[7] = 2 + sprintf((char *) p + 8, "disc-cause-ext=%s", radius[r].term_msg);
320 p[1] = p[7] + 6;
321 p += p[1];
322 }
323 }
306324 }
307325
308326 {
784802
785803 extern int daefd;
786804
787 void processdae(uint8_t *buf, int len, struct sockaddr_in *addr, int alen)
805 void processdae(uint8_t *buf, int len, struct sockaddr_in *addr, int alen, struct in_addr *local)
788806 {
789807 int i, r_code, r_id, length, attribute_length;
790808 uint8_t *packet, attribute;
9931011 LOG(3, s, t, " DAE Disconnect %d (%s)\n", s, session[s].user);
9941012 r_code = DisconnectACK;
9951013
996 sessionshutdown(s, "Requested by PoD", 3, 0); // disconnect session
1014 sessionshutdown(s, "Requested by PoD", CDN_ADMIN_DISC, TERM_ADMIN_RESET); // disconnect session
9971015 break;
9981016
9991017 case CoARequest: // Change of Authorization
10621080 LOG(3, 0, 0, "Sending DAE %s, id=%d\n", radius_code(r_code), r_id);
10631081
10641082 // send DAE response
1065 if (sendto(daefd, buf, len, MSG_DONTWAIT | MSG_NOSIGNAL, (struct sockaddr *) addr, alen) < 0)
1083 if (sendtofrom(daefd, buf, len, MSG_DONTWAIT | MSG_NOSIGNAL, (struct sockaddr *) addr, alen, local) < 0)
10661084 LOG(0, 0, 0, "Error sending DAE response packet: %s\n", strerror(errno));
10671085 }
44
55 /* session control */
66
7 char const *cvs_id = "$Id: sessionctl.c,v 1.4 2005/10/11 09:04:53 bodea Exp $";
7 char const *cvs_id = "$Id: sessionctl.c,v 1.5 2006/04/13 11:14:35 bodea Exp $";
88
99 int plugin_api_version = PLUGIN_API_VERSION;
1010 static struct pluginfuncs *f = 0;
5757 reason = "Requested by administrator.";
5858
5959 if (data->argv[0][0] == 'd')
60 f->sessionshutdown(session, reason, 3, 0);
60 f->sessionshutdown(session, reason, CDN_ADMIN_DISC, TERM_ADMIN_RESET);
6161 else
6262 f->sessionkill(session, reason);
6363
+128
-49
util.c less more
00 /* Misc util functions */
11
2 char const *cvs_id_util = "$Id: util.c,v 1.13 2005/09/19 00:29:12 bodea Exp $";
2 char const *cvs_id_util = "$Id: util.c,v 1.14 2006/04/05 01:45:57 bodea Exp $";
33
44 #include <unistd.h>
55 #include <errno.h>
1919 // to use
2020 char *fmtaddr(in_addr_t addr, int n)
2121 {
22 static char addrs[4][16];
23 struct in_addr in;
22 static char addrs[4][16];
23 struct in_addr in;
2424
25 if (n < 0 || n >= 4) return "";
26 in.s_addr = addr;
27 return strcpy(addrs[n], inet_ntoa(in));
25 if (n < 0 || n >= 4)
26 return "";
27
28 in.s_addr = addr;
29 return strcpy(addrs[n], inet_ntoa(in));
2830 }
2931
3032 void *shared_malloc(unsigned int size)
3133 {
32 void * p;
33 p = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0);
34 void * p;
35 p = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0);
3436
35 if (p == MAP_FAILED)
36 p = NULL;
37 if (p == MAP_FAILED)
38 p = NULL;
3739
38 return p;
40 return p;
3941 }
4042
4143 extern int forked;
4446
4547 pid_t fork_and_close()
4648 {
47 pid_t pid = fork();
48 int i;
49 pid_t pid = fork();
50 int i;
4951
50 if (pid)
51 return pid;
52 if (pid)
53 return pid;
5254
53 forked++;
54 if (config->scheduler_fifo)
55 forked++;
56 if (config->scheduler_fifo)
57 {
58 struct sched_param params = {0};
59 params.sched_priority = 0;
60 if (sched_setscheduler(0, SCHED_OTHER, &params))
5561 {
56 struct sched_param params = {0};
57 params.sched_priority = 0;
58 if (sched_setscheduler(0, SCHED_OTHER, &params))
59 {
60 LOG(0, 0, 0, "Error setting scheduler to OTHER after fork: %s\n", strerror(errno));
61 LOG(0, 0, 0, "This is probably really really bad.\n");
62 }
62 LOG(0, 0, 0, "Error setting scheduler to OTHER after fork: %s\n", strerror(errno));
63 LOG(0, 0, 0, "This is probably really really bad.\n");
6364 }
65 }
6466
65 signal(SIGPIPE, SIG_DFL);
66 signal(SIGCHLD, SIG_DFL);
67 signal(SIGHUP, SIG_DFL);
68 signal(SIGUSR1, SIG_DFL);
69 signal(SIGQUIT, SIG_DFL);
70 signal(SIGKILL, SIG_DFL);
71 signal(SIGTERM, SIG_DFL);
67 signal(SIGPIPE, SIG_DFL);
68 signal(SIGCHLD, SIG_DFL);
69 signal(SIGHUP, SIG_DFL);
70 signal(SIGUSR1, SIG_DFL);
71 signal(SIGQUIT, SIG_DFL);
72 signal(SIGKILL, SIG_DFL);
73 signal(SIGTERM, SIG_DFL);
7274
73 // Close sockets
74 if (clifd != -1) close(clifd);
75 if (cluster_sockfd != -1) close(cluster_sockfd);
76 if (tunfd != -1) close(tunfd);
77 if (udpfd != -1) close(udpfd);
78 if (controlfd != -1) close(controlfd);
79 if (daefd != -1) close(daefd);
80 if (snoopfd != -1) close(snoopfd);
81 if (ifrfd != -1) close(ifrfd);
82 if (ifr6fd != -1) close(ifr6fd);
83 if (rand_fd != -1) close(rand_fd);
84 if (epollfd != -1) close(epollfd);
75 // Close sockets
76 if (clifd != -1) close(clifd);
77 if (cluster_sockfd != -1) close(cluster_sockfd);
78 if (tunfd != -1) close(tunfd);
79 if (udpfd != -1) close(udpfd);
80 if (controlfd != -1) close(controlfd);
81 if (daefd != -1) close(daefd);
82 if (snoopfd != -1) close(snoopfd);
83 if (ifrfd != -1) close(ifrfd);
84 if (ifr6fd != -1) close(ifr6fd);
85 if (rand_fd != -1) close(rand_fd);
86 if (epollfd != -1) close(epollfd);
8587
86 for (i = 0; radfds && i < RADIUS_FDS; i++)
87 close(radfds[i]);
88 for (i = 0; radfds && i < RADIUS_FDS; i++)
89 close(radfds[i]);
90
8891 #ifdef BGP
89 for (i = 0; i < BGP_NUM_PEERS; i++)
90 if (bgp_peers[i].sock != -1)
91 close(bgp_peers[i].sock);
92 for (i = 0; i < BGP_NUM_PEERS; i++)
93 if (bgp_peers[i].sock != -1)
94 close(bgp_peers[i].sock);
9295 #endif /* BGP */
9396
94 return pid;
97 return pid;
9598 }
99
100 ssize_t recvfromto(int s, void *buf, size_t len, int flags,
101 struct sockaddr *from, socklen_t *fromlen, struct in_addr *toaddr)
102 {
103 ssize_t r;
104 struct msghdr msg;
105 struct cmsghdr *cmsg;
106 struct iovec vec;
107 char cbuf[128];
108
109 memset(&msg, 0, sizeof(msg));
110 msg.msg_name = from;
111 msg.msg_namelen = *fromlen;
112
113 vec.iov_base = buf;
114 vec.iov_len = len;
115 msg.msg_iov = &vec;
116 msg.msg_iovlen = 1;
117 msg.msg_flags = 0;
118
119 msg.msg_control = cbuf;
120 msg.msg_controllen = sizeof(cbuf);
121
122 if ((r = recvmsg(s, &msg, flags)) < 0)
123 return r;
124
125 if (fromlen)
126 *fromlen = msg.msg_namelen;
127
128 memset(toaddr, 0, sizeof(*toaddr));
129 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
130 {
131 if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO)
132 {
133 struct in_pktinfo *i = (struct in_pktinfo *) CMSG_DATA(cmsg);
134 memcpy(toaddr, &i->ipi_addr, sizeof(*toaddr));
135 break;
136 }
137 }
138
139 return r;
140 }
141
142 ssize_t sendtofrom(int s, void const *buf, size_t len, int flags,
143 struct sockaddr const *to, socklen_t tolen, struct in_addr const *from)
144 {
145 struct msghdr msg;
146 struct cmsghdr *cmsg;
147 struct iovec vec;
148 struct in_pktinfo pktinfo;
149 char cbuf[CMSG_SPACE(sizeof(pktinfo))];
150
151 memset(&msg, 0, sizeof(msg));
152 msg.msg_name = (struct sockaddr *) to;
153 msg.msg_namelen = tolen;
154
155 vec.iov_base = (void *) buf;
156 vec.iov_len = len;
157 msg.msg_iov = &vec;
158 msg.msg_iovlen = 1;
159 msg.msg_flags = 0;
160
161 msg.msg_control = cbuf;
162 msg.msg_controllen = sizeof(cbuf);
163
164 cmsg = CMSG_FIRSTHDR(&msg);
165 cmsg->cmsg_level = SOL_IP;
166 cmsg->cmsg_type = IP_PKTINFO;
167 cmsg->cmsg_len = CMSG_LEN(sizeof(pktinfo));
168
169 memset(&pktinfo, 0, sizeof(pktinfo));
170 memcpy(&pktinfo.ipi_spec_dst, from, sizeof(*from));
171 memcpy(CMSG_DATA(cmsg), &pktinfo, sizeof(pktinfo));
172
173 return sendmsg(s, &msg, flags);
174 }
33 char *fmtaddr(in_addr_t addr, int n);
44 void *shared_malloc(unsigned int size);
55 pid_t fork_and_close(void);
6 ssize_t sendtofrom(int s, void const *buf, size_t len, int flags,
7 struct sockaddr const *to, socklen_t tolen, struct in_addr const *from);
8
9 ssize_t recvfromto(int s, void *buf, size_t len, int flags,
10 struct sockaddr *from, socklen_t *fromlen, struct in_addr *toaddr);
611
712 #endif /* __UTIL_H__ */