From: fendo Date: Thu, 11 Sep 2014 14:19:57 +0000 (+0200) Subject: Add DHCPv6 functionality. X-Git-Tag: 2.2.1-2fdn3.13 X-Git-Url: http://git.sameswireless.fr/l2tpns.git/commitdiff_plain/b3f40f41f7de7a383c6f1170e546d0b09cc57338?hp=-c Add DHCPv6 functionality. --- b3f40f41f7de7a383c6f1170e546d0b09cc57338 diff --git a/Docs/l2tpns.8 b/Docs/l2tpns.8 index 3f949e4..1bac4fe 100644 --- a/Docs/l2tpns.8 +++ b/Docs/l2tpns.8 @@ -1,70 +1,248 @@ -.\" -*- nroff -*- -.de Id -.ds Dt \\$4 \\$5 +.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp .. -.Id $Id: l2tpns.8,v 1.4 2005-06-12 06:09:35 bodea Exp $ -.TH L2TPNS 8 "\*(Dt" L2TPNS "System Management Commands" -.SH NAME +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "L2TPNS.8 1" +.TH L2TPNS.8 1 "2014-09-11" "perl v5.14.2" "User Contributed Perl Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" l2tpns \- Layer 2 tunneling protocol network server (LNS) -.SH SYNOPSIS -.B l2tpns -.RB [ \-d ] -.RB [ \-v ] -.RB [ \-c -.IR file ] -.RB [ \-h -.IR hostname ] -.SH DESCRIPTION -.B l2tpns -is a daemon for terminating layer 2 tunneling protocol (L2TP: RFC -2661) sessions. +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +\&\fBl2tpns\fR [\-\fBd\fR] [\-\fBv\fR] [\-\fBc\fR \fIfile\fR] [\-\fBh\fR \fIhostname\fR] +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\fBl2tpns\fR is a daemon for terminating layer 2 tunneling protocol (L2TP: \s-1RFC2661\s0) sessions. +.PP +\&\fBl2tpns\fR is a complete L2TP implementation. It supports the \s-1LAC\s0, \s-1LNS\s0, \s-1PPPOE\s0 and DHCPv6 server. .PP -Once running, -.B l2tpns -may be controlled by telnetting to port 23 on the machine running the -daemon and with the -.B nsctl -utility. -.SH OPTIONS -.TP -.B \-d -Detach from terminal and fork into the background. By default l2tpns -will stay in the foreground. -.TP -.B \-v -Increase verbosity for debugging. Can be used multiple times. -.TP -.BI "\-c " file +Once running, \fBl2tpns\fR may be controlled by telnetting to port 23 on the machine running the daemon and with the \fBnsctl\fR utility. +.SH "OPTIONS" +.IX Header "OPTIONS" +.IP "\fB\-d\fR Detach from terminal and fork into the background. By default l2tpns will stay in the foreground." 4 +.IX Item "-d Detach from terminal and fork into the background. By default l2tpns will stay in the foreground." +\&. +.IP "\fB\-v\fR Increase verbosity for debugging. Can be used multiple times." 4 +.IX Item "-v Increase verbosity for debugging. Can be used multiple times." +\&. +.IP "\fB\-c\fR \fIfile\fR" 4 +.IX Item "-c file" Specify configuration file. -.TP -.BI "\-h " hostname -Force hostname to -.IR hostname . -.SH FILES -.TP -.I /etc/l2tpns/startup-config +.IP "\fB\-h\fR \fIhostname\fR" 4 +.IX Item "-h hostname" +Force hostname to \fIhostname\fR. +.SH "FILES" +.IX Header "FILES" +.IP "\fI/etc/l2tpns/startup\-config\fR" 4 +.IX Item "/etc/l2tpns/startup-config" The default configuration file. -.TP -.I /etc/l2tpns/ip_pool -IP address pool configuration. -.TP -.I /etc/l2tpns/users +.IP "\fI/etc/l2tpns/ip_pool\fR" 4 +.IX Item "/etc/l2tpns/ip_pool" +\&\s-1IP\s0 address pool configuration. +.IP "\fI/etc/l2tpns/users\fR" 4 +.IX Item "/etc/l2tpns/users" Username/password configuration for access to admin interface. -.SH SIGNALS -.TP -.B SIGHUP -Reload the config from disk and re-open log file. -.TP -.BR SIGTERM ", " SIGINT -Stop process. Tunnels and sessions are not terminated. This signal -should be used to stop l2tpns on a cluster node where there are other -machines to continue handling traffic. -.TP -.B SIGQUIT +.SH "SIGNALS" +.IX Header "SIGNALS" +.IP "\fB\s-1SIGHUP\s0\fR Reload the config from disk and re-open log file." 4 +.IX Item "SIGHUP Reload the config from disk and re-open log file." +\&. +.IP "\fB\s-1SIGTERM\s0\fR, \fB\s-1SIGINT\s0\fR" 4 +.IX Item "SIGTERM, SIGINT" +Stop process. Tunnels and sessions are not terminated. This signal should be used to stop l2tpns on a cluster node where there are other machines to continue handling traffic. +.IP "\fB\s-1SIGQUIT\s0\fR" 4 +.IX Item "SIGQUIT" Shut down tunnels and sessions, exit process when complete. -.SH SEE ALSO -.BR startup-config (5), -.BR nsctl (8) -.SH AUTHOR -This manual page was written by Jonathan McDowell , -for the Debian GNU/Linux system (but may be used by others). +.SH "MANAGED RADIUS ATTRIBUTE" +.IX Header "MANAGED RADIUS ATTRIBUTE" +.IP "\fBAscend-Client-Primary-DNS\fR, \fBAscend-Client-Secondary-DNS\fR" 4 +.IX Item "Ascend-Client-Primary-DNS, Ascend-Client-Secondary-DNS" +Specifies a primary and secondary \s-1DNS\s0 server address to send to user. +.IP "\fBDelegated\-IPv6\-Prefix\fR" 4 +.IX Item "Delegated-IPv6-Prefix" +Assign a network address IPv6 prefix to a user by DHCPv6. +.IP "\fBFramed-IP-Address\fR" 4 +.IX Item "Framed-IP-Address" +The address to be configured for the user (IPv4 address of the interface ppp). +.IP "\fBFramed-Route\fR" 4 +.IX Item "Framed-Route" +provides routing information to be configured for the user. +.IP "\fBFramed\-IPv6\-Route\fR" 4 +.IX Item "Framed-IPv6-Route" +Has the same action as \fBDelegated\-IPv6\-Prefix\fR. \fBDelegated\-IPv6\-Prefix\fR is the correct one to use. +.IP "\fBFramed\-IPv6\-Address\fR" 4 +.IX Item "Framed-IPv6-Address" +IPv6 address to be assigned to the user by DHCPv6 (IPv6 address of the interface ppp). +.IP "\fBIdle-Timeout\fR" 4 +.IX Item "Idle-Timeout" +disconnects the session if no data for more than \fBIdle-Timeout\fR (in seconds). +.IP "\fBSession-Timeout\fR" 4 +.IX Item "Session-Timeout" +disconnects the user session when the time \fBSession-Timeout\fR is reached (in seconds). +.IP "\fBTunnel-Type\fR, \fBTunnel-Medium-Type\fR, \fBTunnel-Server-Endpoint\fR, \fBTunnel-Password\fR, \fBTunnel-Assignment-Id\fR" 4 +.IX Item "Tunnel-Type, Tunnel-Medium-Type, Tunnel-Server-Endpoint, Tunnel-Password, Tunnel-Assignment-Id" +attributes returned by the Radius of the remote \s-1LNS\s0 server (\s-1LAC\s0 functionality). +.Sp +example, Radius that return the information of 2 remote \s-1LNS\s0 server with which must be open a L2TP \s-1TUNNEL:\s0 +.RS 4 +.IP "\fBTunnel-Type\fR: 1 = L2TP" 4 +.IX Item "Tunnel-Type: 1 = L2TP" +.PD 0 +.IP "\fBTunnel-Medium-Type\fR: 1 = IPv4" 4 +.IX Item "Tunnel-Medium-Type: 1 = IPv4" +.ie n .IP "\fBTunnel-Password\fR: 1 = ""TheSecretL2TP""" 4 +.el .IP "\fBTunnel-Password\fR: 1 = ``TheSecretL2TP''" 4 +.IX Item "Tunnel-Password: 1 = TheSecretL2TP" +.ie n .IP "\fBTunnel-Server-Endpoint\fR: 1 = ""88.xx.xx.x1""" 4 +.el .IP "\fBTunnel-Server-Endpoint\fR: 1 = ``88.xx.xx.x1''" 4 +.IX Item "Tunnel-Server-Endpoint: 1 = 88.xx.xx.x1" +.ie n .IP "\fBTunnel-Assignment-Id\fR: 1 = ""friendisp_lns1""" 4 +.el .IP "\fBTunnel-Assignment-Id\fR: 1 = ``friendisp_lns1''" 4 +.IX Item "Tunnel-Assignment-Id: 1 = friendisp_lns1" +.IP "\fBTunnel-Type\fR: 2 = L2TP" 4 +.IX Item "Tunnel-Type: 2 = L2TP" +.IP "\fBTunnel-Medium-Type\fR: 2 = IPv4" 4 +.IX Item "Tunnel-Medium-Type: 2 = IPv4" +.ie n .IP "\fBTunnel-Password\fR: 2 = ""TheSecretL2TP""" 4 +.el .IP "\fBTunnel-Password\fR: 2 = ``TheSecretL2TP''" 4 +.IX Item "Tunnel-Password: 2 = TheSecretL2TP" +.ie n .IP "\fBTunnel-Server-Endpoint\fR: 2 = ""88.xx.xx.x2""" 4 +.el .IP "\fBTunnel-Server-Endpoint\fR: 2 = ``88.xx.xx.x2''" 4 +.IX Item "Tunnel-Server-Endpoint: 2 = 88.xx.xx.x2" +.ie n .IP "\fBTunnel-Assignment-Id\fR: 2 = ""friendisp_lns2""" 4 +.el .IP "\fBTunnel-Assignment-Id\fR: 2 = ``friendisp_lns2''" 4 +.IX Item "Tunnel-Assignment-Id: 2 = friendisp_lns2" +.RE +.RS 4 +.RE +.PD +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fBstartup-config\fR(5), \fBnsctl\fR(8) +.SH "AUTHOR" +.IX Header "AUTHOR" +This manual page was written by Jonathan McDowell and Fernando Alves (fendo@sameswifi.fr), for the Debian GNU/Linux system (but may be used by others). diff --git a/Docs/l2tpns.8.pod b/Docs/l2tpns.8.pod new file mode 100644 index 0000000..e2aa240 --- /dev/null +++ b/Docs/l2tpns.8.pod @@ -0,0 +1,151 @@ +=pod + +=head1 NAME + +l2tpns - Layer 2 tunneling protocol network server (LNS) + +=head1 SYNOPSIS + +B [-B] [-B] [-B I] [-B I] + +=head1 DESCRIPTION + +B is a daemon for terminating layer 2 tunneling protocol (L2TP: RFC2661) sessions. + +B is a complete L2TP implementation. It supports the LAC, LNS, PPPOE and DHCPv6 server. + +Once running, B may be controlled by telnetting to port 23 on the machine running the daemon and with the B utility. + +=head1 OPTIONS + +=over + +=item B<-d> Detach from terminal and fork into the background. By default l2tpns will stay in the foreground. + +. + +=item B<-v> Increase verbosity for debugging. Can be used multiple times. + +. + +=item B<-c> I + +Specify configuration file. + +=item B<-h> I + +Force hostname to I. + +=back + +=head1 FILES + +=over + +=item I + +The default configuration file. + +=item I + +IP address pool configuration. + +=item I + +Username/password configuration for access to admin interface. + +=back + +=head1 SIGNALS + +=over + +=item B Reload the config from disk and re-open log file. + +. + +=item B, B + +Stop process. Tunnels and sessions are not terminated. This signal should be used to stop l2tpns on a cluster node where there are other machines to continue handling traffic. + +=item B + +Shut down tunnels and sessions, exit process when complete. + +=back + +=head1 MANAGED RADIUS ATTRIBUTE + +=over + +=item B, B + +Specifies a primary and secondary DNS server address to send to user. + +=item B + +Assign a network address IPv6 prefix to a user by DHCPv6. + +=item B + +The address to be configured for the user (IPv4 address of the interface ppp). + +=item B + +provides routing information to be configured for the user. + +=item B + +Has the same action as B. B is the correct one to use. + +=item B + +IPv6 address to be assigned to the user by DHCPv6 (IPv6 address of the interface ppp). + +=item B + +disconnects the session if no data for more than B (in seconds). + +=item B + +disconnects the user session when the time B is reached (in seconds). + +=item B, B, B, B, B + +attributes returned by the Radius of the remote LNS server (LAC functionality). + +example, Radius that return the information of 2 remote LNS server with which must be open a L2TP TUNNEL: + +=over + +=item B: 1 = L2TP + +=item B: 1 = IPv4 + +=item B: 1 = "TheSecretL2TP" + +=item B: 1 = "88.xx.xx.x1" + +=item B: 1 = "friendisp_lns1" + +=item B: 2 = L2TP + +=item B: 2 = IPv4 + +=item B: 2 = "TheSecretL2TP" + +=item B: 2 = "88.xx.xx.x2" + +=item B: 2 = "friendisp_lns2" + +=back + +=back + +=head1 SEE ALSO + +B(5), B(8) + +=head1 AUTHOR + +This manual page was written by Jonathan McDowell and Fernando Alves (fendo@sameswifi.fr), for the Debian GNU/Linux system (but may be used by others). diff --git a/Docs/manual.html b/Docs/manual.html index 8894599..1c59720 100644 --- a/Docs/manual.html +++ b/Docs/manual.html @@ -60,29 +60,17 @@ H3 {

Overview

-l2tpns a complete L2TP implementation. It supports the LAC, LNS and - PPPOE server.

+l2tpns a complete L2TP implementation. It supports the LAC, LNS, PPPOE and DHCPv6 server.

-L2TP (Layer 2 Tunneling Protocol) is designed to allow any layer 2 -protocol (e.g. Ethernet, PPP) to be tunneled over an IP connection. l2tpns -implements PPP over L2TP only.

+L2TP (Layer 2 Tunneling Protocol) is designed to allow any layer 2 protocol (e.g. Ethernet, PPP) to be tunneled over an IP connection. l2tpns implements PPP over L2TP only.

-There are a couple of other L2TP implementations, of which l2tpd is probably the -most popular. l2tpd also will handle being either end of a tunnel, and -is a lot more configurable than l2tpns. However, due to the way it works, -it is nowhere near as scalable.

+There are a couple of other L2TP implementations, of which l2tpd is probably the most popular. l2tpd also will handle being either end of a tunnel, and is a lot more configurable than l2tpns. However, due to the way it works, it is nowhere near as scalable.

-l2tpns uses the TUN/TAP interface provided by the Linux kernel to receive -and send packets. Using some packet manipulation it doesn't require a -single interface per connection, as l2tpd does.

+l2tpns uses the TUN/TAP interface provided by the Linux kernel to receive and send packets. Using some packet manipulation it doesn't require a single interface per connection, as l2tpd does.

-This allows it to scale extremely well to very high loads and very high -numbers of connections.

+This allows it to scale extremely well to very high loads and very high numbers of connections.

-It also has a plugin architecture which allows custom code to be run -during processing. An example of this is in the walled garden module -included.

+It also has a plugin architecture which allows custom code to be run during processing. An example of this is in the walled garden module included.


Documentation is not my best skill. If you find any problems @@ -167,15 +155,15 @@ only ever be used for working out why it doesn't work at all.

  • log_file (string)
    -This will be where all logging and debugging information is written -to. This may be either a filename, such as /var/log/l2tpns, or -the special magic string syslog:facility, where facility -is any one of the syslog logging facilities, such as local5. +This will be where all logging and debugging information is written to. This may be either a filename, such as /var/log/l2tpns, or the special magic string syslog:facility, where facility is any one of the syslog logging facilities, such as local5.
  • pid_file (string)
    -If set, the process id will be written to the specified file. The -value must be an absolute path. +If set, the process id will be written to the specified file. The value must be an absolute path. +
  • + +
  • random_deviceB> (string)
    +Path to random data source (default /dev/urandom). Use "" to use the rand() library function.
  • l2tp_secret (string)
    @@ -185,8 +173,7 @@ used if the LAC requests authentication.
  • l2tp_mtu (int)
    -MTU of interface for L2TP traffic (default: 1500). Used to set link -MRU and adjust TCP MSS. +MTU of interface for L2TP traffic (default: 1500). Used to set link MRU and adjust TCP MSS.
  • ppp_restart_time (int)
    @@ -231,8 +218,7 @@ session is closed.
  • radius_secret (string)
    -This secret will be used in all RADIUS queries. If this is not set then -RADIUS queries will fail. +This secret will be used in all RADIUS queries. If this is not set then RADIUS queries will fail.
  • radius_authtypes (string)
    @@ -252,11 +238,7 @@ session is established.
  • bind_address (ip address)
    -It's the listen address of the l2tp udp protocol sent and received -to LAC. This address is also assigned to the tun interface if no -iftun_address is specified. Packets containing user traffic should be -routed via this address if given, otherwise the primary address of the -machine. +It's the listen address of the l2tp udp protocol sent and received to LAC. This address is also assigned to the tun interface if no iftun_address is specified. Packets containing user traffic should be routed via this address if given, otherwise the primary address of the machine.
  • iftun_address (ip address)
    @@ -280,7 +262,6 @@ for Address1 on LNS1 and a bgp.prepend(MY_AS) for Address2 on LNS2 example of use with 2 address:
    set bind_multi_address "64.14.13.41, 64.14.13.42" -
  • tundevicename (string)
    @@ -325,11 +306,6 @@ uptxoctets, downrxoctets, origin (optional). The qos field is 1 if a standard us If set to true, all origin of the usage is dumped to the accounting file (LAC+Remote LNS+PPPOE)(default false).
  • -
  • setuid (int)
    -After starting up and binding the interface, change UID to this. This -doesn't work properly. -
  • -
  • dump_speed (boolean)
    If set to true, then the current bandwidth utilization will be logged every second. Even if this is disabled, you can see this information by running diff --git a/Docs/startup-config.5 b/Docs/startup-config.5 index 77af484..e76e269 100644 --- a/Docs/startup-config.5 +++ b/Docs/startup-config.5 @@ -1,367 +1,496 @@ -.\" -*- nroff -*- -.de Id -.ds Dt \\$4 \\$5 +.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp .. -.Id $Id: startup-config.5,v 1.18 2006-07-01 12:40:17 bodea Exp $ -.TH STARTUP-CONFIG 5 "\*(Dt" L2TPNS "File Formats and Conventions" -.SH NAME +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "STARTUP-CONFIG.5 1" +.TH STARTUP-CONFIG.5 1 "2014-09-11" "perl v5.14.2" "User Contributed Perl Documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" startup\-config \- configuration file for l2tpns -.SH SYNOPSIS -/etc/l2tpns/startup-config -.SH DESCRIPTION -.B startup-config -is the configuration file for -.BR l2tpns . +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +/etc/l2tpns/startup\-config +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\fBstartup-config\fR is the configuration file for \fBl2tpns\fR .PP -The format is plain text, in the same format as accepted by the -configuration mode of -.BR l2tpns 's -telnet administrative interface. Comments are indicated by either the -character -.B # -or -.BR ! . -.SS SETTINGS +The format is plain text, in the same format as accepted by +the configuration mode of l2tpns's telnet administrative +interface. Comments are indicated by either the character # or !. +.SS "\s-1SETTINGS\s0" +.IX Subsection "SETTINGS" Settings are specified with -.IP -.BI "set " "variable value" +.IP "\fBset\fR \fIvariable\fR \fIvalue\fR" 4 +.IX Item "set variable value" .PP -The following -.IR variable s -may be set: -.RS -.TP -.B debug -Set the level of debugging messages written to the log file. The -value should be between 0 and 5, with 0 being no debugging, and 5 -being the highest. -.TP -.B log_file -This will be where all logging and debugging information is written -to. This may be either a filename, such as -.BR /var/log/l2tpns , -or the string -.BR syslog : \fIfacility\fR , -where -.I facility -is any one of the syslog logging facilities, such as -.BR local5 . -.TP -.B pid_file -If set, the process id will be written to the specified file. The -value must be an absolute path. -.TP -.B random_device -Path to random data source (default -.BR /dev/urandom ). -Use "" to use the rand() library function. -.TP -.B l2tp_secret -The secret used by -.B l2tpns -for authenticating tunnel request. Must be the same as the LAC, or -authentication will fail. Only actually be used if the LAC requests -authentication. -.TP -.B l2tp_mtu -MTU of interface for L2TP traffic (default: 1500). Used to set link -MRU and adjust TCP MSS. -.TP -.B ppp_restart_time -Restart timer for PPP protocol negotiation in seconds (default: 3). -.TP -.B ppp_max_configure -Number of configure requests to send before giving up (default: 10). -.TP -.B ppp_max_failure -Number of Configure-Nak requests to send before sending a -Configure-Reject (default: 5). -.TP -.BR primary_dns ", " secondary_dns -Whenever a PPP connection is established, DNS servers will be sent to the -user, both a primary and a secondary. If either is set to 0.0.0.0, then that -one will not be sent. -.TP -.BR primary_radius ", " secondary_radius -Sets the RADIUS servers used for both authentication and accounting. -If the primary server does not respond, then the secondary RADIUS -server will be tried. -.TP -.BR primary_radius_port ", " secondary_radius_port -Sets the authentication ports for the primary and secondary RADIUS -servers. The accounting port is one more than the authentication -port. If no ports are given, authentication defaults to 1645, and -accounting to 1646. -.TP -.B radius_accounting -If set to true, then RADIUS accounting packets will be sent. A -.B Start -record will be sent when the session is successfully authenticated, -and a -.B Stop -record when the session is closed. -.TP -.B radius_interim -If -.B radius_accounting -is on, defines the interval between sending of RADIUS interim -accounting records (in seconds). -.TP -.B radius_secret -Secret to be used in RADIUS packets. -.TP -.B radius_authtypes -A comma separated list of supported RADIUS authentication methods -("pap" or "chap"), in order of preference (default "pap"). -.TP -.B radius_dae_port -Port for DAE RADIUS (Packet of Death/Disconnect, Change of Authorization) -requests (default: 3799). -.TP -.BR radius_bind_min ", " radius_bind_max -Define a port range in which to bind sockets used to send and receive -RADIUS packets. Must be at least RADIUS_FDS (64) wide. Simplifies -firewalling of RADIUS ports (default: dynamically assigned). -.TP -.B allow_duplicate_users -Allow multiple logins with the same username. If false (the default), -any prior session with the same username will be dropped when a new -session is established. -.TP -.B guest_account -Allow multiple logins matching this specific username. -.TP -.B bind_address -When the tun interface is created, it is assigned the address -specified here. If no address is given, 1.1.1.1 is used. Packets -containing user traffic should be routed via this address if given, -otherwise the primary address of the machine. -.TP -.B peer_address -Address to send to clients as the default gateway. -.TP -.B send_garp -Determines whether or not to send a gratuitous ARP for the -.B bind_address -when the server is ready to handle traffic (default: true). This -setting is ignored if BGP is configured. -.TP -.B throttle_speed -Sets the default speed (in kbits/s) which sessions will be limited to. -.TP -.B throttle_buckets -Number of token buckets to allocate for throttling. Each throttled -session requires two buckets (in and out). -.TP -.B accounting_dir -If set to a directory, then every 5 minutes the current usage for -every connected use will be dumped to a file in this directory. -.TP -.B dump_speed -If set to true, then the current bandwidth utilization will be logged -every second. Even if this is disabled, you can see this information -by running the -.B uptime -command on the CLI. -.TP -.B multi_read_count -Number of packets to read off each of the UDP and TUN fds when -returned as readable by select (default: 10). Avoids incurring the -unnecessary system call overhead of select on busy servers. -.TP -.B scheduler_fifo -Sets the scheduling policy for the -.B l2tpns -process to -.BR SCHED_FIFO . -This causes the kernel to immediately preempt any currently running -.B SCHED_OTHER -(normal) process in favour of -.B l2tpns -when it becomes runnable. -.br -Ignored on uniprocessor systems. -.TP -.B lock_pages -Keep all pages mapped by the -.B l2tpns -process in memory. -.TP -.B icmp_rate -Maximum number of host unreachable ICMP packets to send per second. -.TP -.B packet_limit -Maximum number of packets of downstream traffic to be handled each -tenth of a second per session. If zero, no limit is applied (default: -0). Intended as a DoS prevention mechanism and not a general -throttling control (packets are dropped, not queued). -.TP -.B cluster_address -Multicast cluster address (default: 239.192.13.13). -.TP -.B cluster_interface +A list of the possible configuration directives follows. Each of these should be set by a line like: +.ie n .IP "\fBset\fR \fIconfigstring\fR \fI""value""\fR" 4 +.el .IP "\fBset\fR \fIconfigstring\fR \fI``value''\fR" 4 +.IX Item "set configstring value" +.PD 0 +.IP "\fBset\fR \fIipaddress\fR \fI192.168.1.1\fR" 4 +.IX Item "set ipaddress 192.168.1.1" +.IP "\fBset\fR \fIboolean\fR \fItrue\fR" 4 +.IX Item "set boolean true" +.PD +.PP +The following \fIvariables\fR may be set: +.IP "\fBaccounting_dir\fR (string)" 4 +.IX Item "accounting_dir (string)" +If set to a directory, then every 5 minutes the current usage for every connected use will be dumped to a file in this directory. Each file dumped begins with a header, where each line is prefixed by #. Following the header is a single line for every connected user, fields separated by a space. +.Sp +The fields are username, ip, qos, uptxoctets, downrxoctets, origin (optional). The qos field is 1 if a standard user, and 2 if the user is throttled. The origin field is dump if \fBaccount_all_origin\fR is set to true (origin value: L=LAC data, R=Remote \s-1LNS\s0 data, P=PPPOE data). +.IP "\fBaccount_all_origin\fR (boolean)" 4 +.IX Item "account_all_origin (boolean)" +If set to true, all origin of the usage is dumped to the accounting file (LAC+Remote \s-1LNS+PPPOE\s0)(default false). +.IP "\fBallow_duplicate_users\fR (boolean)" 4 +.IX Item "allow_duplicate_users (boolean)" +Allow multiple logins with the same username. If false (the default), any prior session with the same username will be dropped when a new session is established. +.IP "\fBauth_tunnel_change_addr_src\fR (boolean)" 4 +.IX Item "auth_tunnel_change_addr_src (boolean)" +This parameter authorize to change the source \s-1IP\s0 of the tunnels l2tp. This parameter can be used when the remotes \s-1BAS/LAC\s0 are l2tpns server configured in cluster mode, but that the interface to remote \s-1LNS\s0 are not clustered (the tunnel can be coming from different source \s-1IP\s0) (default: no). +.IP "\fBbind_address\fR (ip address)" 4 +.IX Item "bind_address (ip address)" +It's the listen address of the l2tp udp protocol sent and received to \s-1LAC\s0. This address is also assigned to the tun interface if no iftun_address is specified. Packets containing user traffic should be routed via this address if given, otherwise the primary address of the machine. +.IP "\fBbind_multi_address\fR (ip address)" 4 +.IX Item "bind_multi_address (ip address)" +This parameter permit to listen several addresss of the l2tp udp protocol (and set several address to the tun interface). +.Sp +\&\s-1WHEN\s0 this parameter is set, It \s-1OVERWRITE\s0 the parameters \*(L"bind_address\*(R" and \*(L"iftun_address\*(R". +.Sp +these can be interesting when you want do load-balancing in cluster mode of the uploaded from the \s-1LAC\s0. For example you can set a bgp.prepend(\s-1MY_AS\s0) for Address1 on \s-1LNS1\s0 and a bgp.prepend(\s-1MY_AS\s0) for Address2 on \s-1LNS2\s0 (see \s-1BGP\s0 AS-path prepending). +.Sp +example of use with 2 address: +.Sp +\&\fBset\fR \fIbind_multi_address\fR \*(L"64.14.13.41, 64.14.13.42\*(R" +.IP "\fBcluster_address\fR (ip address)" 4 +.IX Item "cluster_address (ip address)" +Multicast cluster address (default: 239.192.13.13). See the section on Clustering for more information. +.IP "\fBcluster_interface\fR (string)" 4 +.IX Item "cluster_interface (string)" Interface for cluster packets (default: eth0). -.TP -.B cluster_mcast_ttl -TTL for multicast packets (default: 1). -.TP -.B cluster_hb_interval +.IP "\fBcluster_mcast_ttl\fR (int)" 4 +.IX Item "cluster_mcast_ttl (int)" +\&\s-1TTL\s0 for multicast packets (default: 1). +.IP "\fBcluster_hb_interval\fR (int)" 4 +.IX Item "cluster_hb_interval (int)" Interval in tenths of a second between cluster heartbeat/pings. -.TP -.B cluster_hb_timeout -Cluster heartbeat timeout in tenths of a second. A new master will be -elected when this interval has been passed without seeing a heartbeat -from the master. -.TP -.B cluster_master_min_adv -Determines the minumum number of up to date slaves required before the -master will drop routes (default: 1). -.TP -.B ipv6_prefix -Enable negotiation of IPv6. This forms the the first 64 bits of the -client allocated address. The remaining 64 come from the allocated -IPv4 address and 4 bytes of 0s. +.IP "\fBcluster_hb_timeout\fR (int)" 4 +.IX Item "cluster_hb_timeout (int)" +Cluster heartbeat timeout in tenths of a second. A new master will be elected when this interval has been passed without seeing a heartbeat from the master. +.IP "\fBcluster_master_min_adv\fR (int)" 4 +.IX Item "cluster_master_min_adv (int)" +Determines the minumum number of up to date slaves required before the master will drop routes (default: 1). +.IP "\fBdebug\fR (int)" 4 +.IX Item "debug (int)" +Set the level of debugging messages written to the log file. The value should +be between 0 and 5, with 0 being no debugging, and 5 being the highest. +A rough description of the levels is: +.RS 4 +.IP "0. Critical Errors \- Things are probably broken" 4 +.IX Item "0. Critical Errors - Things are probably broken" +.PD 0 +.IP "1. Errors \- Things might have gone wrong, but probably will recover" 4 +.IX Item "1. Errors - Things might have gone wrong, but probably will recover" +.IP "2. Warnings \- Just in case you care what is not quite perfect" 4 +.IX Item "2. Warnings - Just in case you care what is not quite perfect" +.IP "3. Information \- Parameters of control packets" 4 +.IX Item "3. Information - Parameters of control packets" +.IP "4. Calls \- For tracing the execution of the code" 4 +.IX Item "4. Calls - For tracing the execution of the code" +.IP "5. Packets \- Everything, including a hex dump of all packets processed... probably twice" 4 +.IX Item "5. Packets - Everything, including a hex dump of all packets processed... probably twice" +.RE +.RS 4 +.PD +.Sp +Note that the higher you set the debugging level, the slower the program will run. Also, at level 5 a \s-1LOT\s0 of information will be logged. This should only ever be used for working out why it doesn't work at all. .RE -.SS BGP ROUTING +.IP "\fBdump_speed\fR (boolean)" 4 +.IX Item "dump_speed (boolean)" +If set to true, then the current bandwidth utilization will be logged every second. Even if this is disabled, you can see this information by running the uptime command on the \s-1CLI\s0. +.IP "\fBdisable_sending_hello\fR (boolean)" 4 +.IX Item "disable_sending_hello (boolean)" +Disable l2tp sending \s-1HELLO\s0 message for Apple compatibility. Some \s-1OS\s0 X implementation of l2tp no manage the L2TP \*(L"\s-1HELLO\s0 message\*(R". (default: no). +.IP "\fBecho_timeout\fR (int)" 4 +.IX Item "echo_timeout (int)" +Time between last packet sent and \s-1LCP\s0 \s-1ECHO\s0 generation (default: 10 (seconds)). +.IP "\fBguest_account\fR" 4 +.IX Item "guest_account" +Allow multiple logins matching this specific username. +.IP "\fBicmp_rate\fR (int)" 4 +.IX Item "icmp_rate (int)" +Maximum number of host unreachable \s-1ICMP\s0 packets to send per second. +.IP "\fBidle_echo_timeout\fR (int)" 4 +.IX Item "idle_echo_timeout (int)" +Drop sessions who have not responded within idle_echo_timeout seconds (default: 240 (seconds)) +.IP "\fBiftun_address\fR (ip address)" 4 +.IX Item "iftun_address (ip address)" +This parameter is used when you want a tun interface address different from the address of \*(L"bind_address\*(R" (For use in cases of specific configuration). If no address is given to iftun_address and bind_address, 1.1.1.1 is used. +.IP "\fBl2tp_mtu\fR (int)" 4 +.IX Item "l2tp_mtu (int)" +\&\s-1MTU\s0 of interface for L2TP traffic (default: 1500). Used to set link \s-1MRU\s0 and adjust \s-1TCP\s0 \s-1MSS\s0. +.IP "\fBl2tp_secret\fR (string)" 4 +.IX Item "l2tp_secret (string)" +The secret used by l2tpns for authenticating tunnel request. Must be the same as the \s-1LAC\s0, or authentication will fail. Only actually be used if the \s-1LAC\s0 requests authentication. +.IP "\fBlock_pages\fR (boolean)" 4 +.IX Item "lock_pages (boolean)" +Keep all pages mapped by the l2tpns process in memory. +.IP "\fBlog_file\fR (string)" 4 +.IX Item "log_file (string)" +This will be where all logging and debugging information is written to.This may be either a filename, such as /var/log/l2tpns, or the string syslog:facility, where facility is any one of the syslog logging facilities, such as local5. +.IP "\fBmulti_read_count\fR (int)" 4 +.IX Item "multi_read_count (int)" +Number of packets to read off each of the \s-1UDP\s0 and \s-1TUN\s0 fds when returned as readable by select (default: 10). Avoids incurring the unnecessary system call overhead of select on busy servers. +.IP "\fBpacket_limit\fR (int>" 4 +.IX Item "packet_limit (int>" +Maximum number of packets of downstream traffic to be handled each tenth of a second per session. If zero, no limit is applied (default: 0). Intended as a DoS prevention mechanism and not a general throttling control (packets are dropped, not queued). +.IP "\fBpeer_address\fR (ip address)" 4 +.IX Item "peer_address (ip address)" +Address to send to clients as the default gateway. +.IP "\fBpid_file\fR (string)" 4 +.IX Item "pid_file (string)" +If set, the process id will be written to the specified file. The value must be an absolute path. +.IP "\fBppp_restart_time\fR (int)" 4 +.IX Item "ppp_restart_time (int)" +.PD 0 +.IP "\fBppp_max_configure\fR (int)" 4 +.IX Item "ppp_max_configure (int)" +.IP "\fBppp_max_failure\fR (int)" 4 +.IX Item "ppp_max_failure (int)" +.PD +\&\s-1PPP\s0 counter and timer values, as described in Section 4.1 of \s-1RFC1661\s0. +.Sp +\&\fIppp_restart_time\fR, Restart timer for \s-1PPP\s0 protocol negotiation in seconds (default: 3). +.Sp +\&\fIppp_max_configure\fR, Number of configure requests to send before giving up (default: 10). +.Sp +\&\fIppp_max_failure\fR, Number of Configure-Nak requests to send before sending a Configure-Reject (default: 5). +.IP "\fBprimary_dns\fR (ip address), \fBsecondary_dns\fR (ip address)" 4 +.IX Item "primary_dns (ip address), secondary_dns (ip address)" +Whenever a \s-1PPP\s0 connection is established, \s-1DNS\s0 servers will be sent to the user, both a primary and a secondary. If either is set to 0.0.0.0, then that one will not be sent. +.IP "\fBprimary_radius\fR (ip address), \fBsecondary_radius\fR (ip address)" 4 +.IX Item "primary_radius (ip address), secondary_radius (ip address)" +Sets the \s-1RADIUS\s0 servers used for both authentication and accounting. If the primary server does not respond, then the secondary \s-1RADIUS\s0 server will be tried. +.Sp +Note: in addition to the source \s-1IP\s0 address and identifier, the \s-1RADIUS\s0 server must include the source port when detecting duplicates to supress (in order to cope with a large number of sessions comming on-line simultaneously l2tpns uses a set of udp sockets, each with a seperate identifier). +.IP "\fBprimary_radius_port\fR (short), \fBsecondary_radius_port\fR (short)" 4 +.IX Item "primary_radius_port (short), secondary_radius_port (short)" +Sets the authentication ports for the primary and secondary \s-1RADIUS\s0 servers. The accounting port is one more than the authentication port. If no \s-1RADIUS\s0 ports are given, the authentication port defaults to 1645, and the accounting port to 1646. +.IP "\fBradius_accounting\fR (boolean)" 4 +.IX Item "radius_accounting (boolean)" +If set to true, then \s-1RADIUS\s0 accounting packets will be sent. This means that a \fBStart\fR record will be sent when the session is successfully authenticated, and a \fBStop\fR record will be sent when the session is closed. +.IP "\fBradius_interim\fR (int)" 4 +.IX Item "radius_interim (int)" +If radius_accounting is on, defines the interval between sending of \s-1RADIUS\s0 interim accounting records (in seconds). +.IP "\fBradius_secret\fR (string)" 4 +.IX Item "radius_secret (string)" +This secret will be used in all \s-1RADIUS\s0 queries. If this is not set then \s-1RADIUS\s0 queries will fail. +.IP "\fBradius_authtypes\fR (string)" 4 +.IX Item "radius_authtypes (string)" +A comma separated list of supported \s-1RADIUS\s0 authentication methods (\*(L"pap\*(R" or \*(L"chap\*(R"), in order of preference (default \*(L"pap\*(R"). +.IP "\fBradius_dae_port\fR (short)" 4 +.IX Item "radius_dae_port (short)" +Port for \s-1DAE\s0 \s-1RADIUS\s0 (Packet of Death/Disconnect, Change of Authorization) requests (default: 3799). +.IP "\fBradius_bind_min\fR, \fBradius_bind_max\fR (int)" 4 +.IX Item "radius_bind_min, radius_bind_max (int)" +Define a port range in which to bind sockets used to send and receive \s-1RADIUS\s0 packets. Must be at least \s-1RADIUS_FDS\s0 (64) wide. Simplifies firewalling of \s-1RADIUS\s0 ports (default: dynamically assigned). +.IP "\fBrandom_device\fR (string)" 4 +.IX Item "random_device (string)" +Path to random data source (default /dev/urandom). Use "" to use the \fIrand()\fR library function. +.IP "\fBscheduler_fifo\fR (boolean)" 4 +.IX Item "scheduler_fifo (boolean)" +Sets the scheduling policy for the l2tpns process to \s-1SCHED_FIFO\s0. This causes the kernel to immediately preempt any currently running \s-1SCHED_OTHER\s0 (normal) process in favour of l2tpns when it becomes runnable. Ignored on uniprocessor systems. +.IP "\fBsend_garp\fR (boolean)" 4 +.IX Item "send_garp (boolean)" +Determines whether or not to send a gratuitous \s-1ARP\s0 for the bind_address when the server is ready to handle traffic (default: true). This value is ignored if \s-1BGP\s0 is configured. +.IP "\fBtundevicename\fR (string)" 4 +.IX Item "tundevicename (string)" +Name of the tun interface (default: \*(L"tun0\*(R"). +.IP "\fBthrottle_speed\fR (int)" 4 +.IX Item "throttle_speed (int)" +Sets the default speed (in kbits/s) which sessions will be limited to. If this is set to 0, then throttling will not be used at all. Note: You can set this by the \s-1CLI\s0, but changes will not affect currently connected users. +.IP "\fBthrottle_buckets\fR (int)" 4 +.IX Item "throttle_buckets (int)" +Number of token buckets to allocate for throttling. Each throttled session requires two buckets (in and out). +.SS "DHCPv6 And IPv6 \s-1SETTINGS\s0" +.IX Subsection "DHCPv6 And IPv6 SETTINGS" +.IP "\fBdhcp6_preferred_lifetime\fR (int)" 4 +.IX Item "dhcp6_preferred_lifetime (int)" +The preferred lifetime for the IPv6 address and the IPv6 prefix address, expressed in units of seconds (see rfc3315). +.IP "\fBdhcp6_valid_lifetime\fR (int)" 4 +.IX Item "dhcp6_valid_lifetime (int)" +The valid lifetime for the IPv6 address and the IPv6 prefix address, expressed in units of seconds (see rfc3315). +.IP "\fBdhcp6_server_duid\fR (int)" 4 +.IX Item "dhcp6_server_duid (int)" +\&\s-1DUID\s0 Based on Link-layer Address (DUID-LL) (see rfc3315). +.IP "\fBprimary_ipv6_dns\fR, \fBsecondary_ipv6_dns\fR (Ipv6 address)" 4 +.IX Item "primary_ipv6_dns, secondary_ipv6_dns (Ipv6 address)" +IPv6 \s-1DNS\s0 servers will be sent to the user (see rfc3646). +.IP "\fBdefault_ipv6_domain_list\fR (string)" 4 +.IX Item "default_ipv6_domain_list (string)" +The Domain Search List (ex: \*(L"fdn.fr\*(R") (see rfc3646). +.IP "\fBipv6_prefix\fR (Ipv6 address)" 4 +.IX Item "ipv6_prefix (Ipv6 address)" +Enable negotiation of IPv6. This forms the the first 64 bits of the client allocated address. The remaining 64 come from the allocated IPv4 address and 4 bytes of 0. +.SS "\s-1LAC\s0 \s-1SETTINGS\s0" +.IX Subsection "LAC SETTINGS" +.IP "\fBbind_address_remotelns\fR (ip address)" 4 +.IX Item "bind_address_remotelns (ip address)" +Address of the interface to listen the remote \s-1LNS\s0 tunnels. If no address is given, all interfaces are listened (Any Address). +.IP "\fBbind_portremotelns\fR (short)" 4 +.IX Item "bind_portremotelns (short)" +Port to bind for the Remote \s-1LNS\s0 (default: 65432). +.PP +A static \s-1REMOTES\s0 \s-1LNS\s0 configuration can be entered by the command: +.IP "\fBsetforward\fR \fI\s-1MASK\s0\fR \fI\s-1IP\s0\fR \fI\s-1PORT\s0\fR \fI\s-1SECRET\s0\fR" 4 +.IX Item "setforward MASK IP PORT SECRET" +where \s-1MASK\s0 specifies the mask of users who have forwarded to remote \s-1LNS\s0 (ex: \*(L"/friendISP@company.com\*(R"). +.Sp +where \s-1IP\s0 specifies the \s-1IP\s0 of the remote \s-1LNS\s0 (ex: \*(L"66.66.66.55\*(R"). +.Sp +where \s-1PORT\s0 specifies the L2TP Port of the remote \s-1LNS\s0 (Normally should be 1701) (ex: 1701). +.Sp +where \s-1SECRET\s0 specifies the secret password the remote \s-1LNS\s0 (ex: mysecret). +.PP +The static \s-1REMOTE\s0 \s-1LNS\s0 configuration can be used when the friend \s-1ISP\s0 not have a proxied Radius. +.PP +If a proxied Radius is used, It will return the \s-1RADIUS\s0 attributes: +.IP "Tunnel\-Type:1 = L2TP" 4 +.IX Item "Tunnel-Type:1 = L2TP" +.PD 0 +.IP "Tunnel\-Medium\-Type:1 = IPv4" 4 +.IX Item "Tunnel-Medium-Type:1 = IPv4" +.ie n .IP "Tunnel\-Password:1 = ""\s-1LESECRETL2TP\s0""" 4 +.el .IP "Tunnel\-Password:1 = ``\s-1LESECRETL2TP\s0''" 4 +.IX Item "Tunnel-Password:1 = LESECRETL2TP" +.ie n .IP "Tunnel\-Server\-Endpoint:1 = ""88.xx.xx.x1""" 4 +.el .IP "Tunnel\-Server\-Endpoint:1 = ``88.xx.xx.x1''" 4 +.IX Item "Tunnel-Server-Endpoint:1 = 88.xx.xx.x1" +.ie n .IP "Tunnel\-Assignment\-Id:1 = ""friendisp_lns1""" 4 +.el .IP "Tunnel\-Assignment\-Id:1 = ``friendisp_lns1''" 4 +.IX Item "Tunnel-Assignment-Id:1 = friendisp_lns1" +.IP "Tunnel\-Type:2 += L2TP" 4 +.IX Item "Tunnel-Type:2 += L2TP" +.IP "Tunnel\-Medium\-Type:2 += IPv4" 4 +.IX Item "Tunnel-Medium-Type:2 += IPv4" +.ie n .IP "Tunnel\-Password:2 += ""\s-1LESECRETL2TP\s0""" 4 +.el .IP "Tunnel\-Password:2 += ``\s-1LESECRETL2TP\s0''" 4 +.IX Item "Tunnel-Password:2 += LESECRETL2TP" +.ie n .IP "Tunnel\-Server\-Endpoint:2 += ""88.xx.xx.x2""" 4 +.el .IP "Tunnel\-Server\-Endpoint:2 += ``88.xx.xx.x2''" 4 +.IX Item "Tunnel-Server-Endpoint:2 += 88.xx.xx.x2" +.ie n .IP "Tunnel\-Assignment\-Id:2 += ""friendisp_lns2""" 4 +.el .IP "Tunnel\-Assignment\-Id:2 += ``friendisp_lns2''" 4 +.IX Item "Tunnel-Assignment-Id:2 += friendisp_lns2" +.PD +.SS "\s-1PPPOE\s0 \s-1SETTINGS\s0" +.IX Subsection "PPPOE SETTINGS" +.IP "\fBpppoe_if_to_bind\fR (string)" 4 +.IX Item "pppoe_if_to_bind (string)" +\&\s-1PPPOE\s0 server interface to bind (ex: \*(L"eth0.12\*(R"), If not specified the server \s-1PPPOE\s0 is not enabled. For the pppoe clustering, all the interfaces \s-1PPPOE\s0 of the clusters must use the same \s-1HW\s0 address (\s-1MAC\s0 address). +.IP "\fBpppoe_service_name\fR (string)" 4 +.IX Item "pppoe_service_name (string)" +\&\s-1PPPOE\s0 service name (default: \s-1NULL\s0). +.IP "\fBpppoe_ac_name\fR (string)" 4 +.IX Item "pppoe_ac_name (string)" +\&\s-1PPPOE\s0 access concentrator name (default: \*(L"l2tpns\-pppoe\*(R"). +.IP "\fBpppoe_only_equal_svc_name\fR (boolean)" 4 +.IX Item "pppoe_only_equal_svc_name (boolean)" +If set to yes, the \s-1PPPOE\s0 server only accepts clients with a \*(L"service-name\*(R" different from \s-1NULL\s0 and a \*(L"service-name\*(R" equal to server \*(L"service-name\*(R" (default: no). +.SS "\s-1BGP\s0 \s-1ROUTING\s0" +.IX Subsection "BGP ROUTING" The routing configuration section is entered by the command -.IP -.BI "router bgp " as .PP -where -.I as -specifies the local AS number. +\&\fBrouter\fR \fBbgp\fR \fIas\fR +.PP +where \fIas\fR specifies the local \s-1AS\s0 number. +.PP +Subsequent lines prefixed with \fBneighbour\fR \fIpeer\fR define the attributes of \s-1BGP\s0 neighhbours. Valid commands are: .PP -Subsequent lines prefixed with -.BI "neighbour " peer -define the attributes of BGP neighhbours. Valid commands are: -.IP -.BI "neighbour " peer " remote-as " as -.br -.BI "neighbour " peer " timers " "keepalive hold" +\&\fBneighbour\fR \fIpeer\fR \fBremote-as\fR \fIas\fR .PP -Where -.I peer -specifies the BGP neighbour as either a hostname or IP address, -.I as -is the remote AS number and -.IR keepalive , -.I hold -are the timer values in seconds. -.SS NAMED ACCESS LISTS +\&\fBneighbour\fR \fIpeer\fR \fBtimers\fR \fIkeepalive\fR \fIhold\fR +.PP +Where \fIpeer\fR specifies the \s-1BGP\s0 neighbour as either a hostname or \s-1IP\s0 address, \fIas\fR is the remote \s-1AS\s0 number and \fIkeepalive\fR, \fIhold\fR are the timer values in seconds. +.SS "\s-1NAMED\s0 \s-1ACCESS\s0 \s-1LISTS\s0" +.IX Subsection "NAMED ACCESS LISTS" Named access lists may be defined with either of -.IP -.BI "ip access\-list standard " name -.br -.BI "ip access\-list extended " name +.IP "\(bu" 4 +\&\fBip\fR \fBaccess-list\fR \fBstandard\fR \fIname\fR +.IP "\(bu" 4 +\&\fBip\fR \fBaccess-list\fR \fBextended\fR \fIname\fR +.PP +Subsequent lines starting with permit or deny define the body of the access-list. .PP -Subsequent lines starting with -.B permit -or -.B deny -define the body of the access\-list. +\fIStandard Access Lists\fR +.IX Subsection "Standard Access Lists" .PP -.B Standard Access Lists -.RS 4n Standard access lists are defined with: -.IP -.RB { permit | deny } -.IR source " [" dest ] +.IP "\(bu" 4 +{\fBpermit\fR|\fBdeny\fR} \fIsource\fR [\fIdest\fR] .PP -Where -.I source -and -.I dest -specify IP matches using one of: -.IP -.I address -.I wildard -.br -.B host -.I address -.br -.B any +Where \fIsource\fR and \fIdest\fR specify \s-1IP\s0 matches using one of: +.IP "\(bu" 4 +\&\fIaddress\fR \fIwildard\fR +.IP "\(bu" 4 +\&\fBhost\fR \fIaddress\fR +.IP "\(bu" 4 +\&\fBany\fR .PP -.I address -and -.I wildard -are in dotted-quad notation, bits in the -.I wildard -indicate which address bits in -.I address -are relevant to the match (0 = exact match; 1 = don't care). +\&\fIaddress\fR and \fIwildard\fR are in dotted-quad notation, bits in the \fIwildard\fR indicate which address bits in \fIaddress\fR are relevant to the match (0 = exact match; 1 = don't care). .PP -The shorthand -.RB ' host -.IR address ' -is equivalent to -.RI ' address -.BR 0.0.0.0 '; -.RB ' any ' -to -.RB ' 0.0.0.0 -.BR 255.255.255.255 '. -.RE +The shorthand 'host address' is equivalent to '\fIaddress\fR \fB0.0.0.0\fR'; '\fBany\fR' to '\fB0.0.0.0\fR \fB255.255.255.255\fR'. +.PP +\fIExtended Access Lists\fR +.IX Subsection "Extended Access Lists" .PP -.B Extended Access Lists -.RS 4n Extended access lists are defined with: -.IP -.RB { permit | deny } -.I proto -.IR source " [" ports "] " dest " [" ports "] [" flags ] +.IP "\(bu" 4 +{\fBpermit\fR|\fBdeny\fR} \fIproto\fR \fIsource\fR [\fIports\fR] \fIdest\fR [\fIports\fR] [\fIflags\fR] .PP -Where -.I proto -is one of -.BR ip , -.B tcp -or -.BR udp , -and -.I source -and -.I dest -are as described above for standard lists. +Where \fIproto\fR is one of \fBip\fR, \fBtcp\fR or \fBudp\fR, and \fIsource\fR and \fIdest\fR are as described above for standard lists. .PP -For TCP and UDP matches, source and destination may be optionally -followed by a -.I ports -specification: -.IP -.RB { eq | neq | gt | lt } -.I port -.br -.B -range -.I from to +For \s-1TCP\s0 and \s-1UDP\s0 matches, source and destination may be optionally followed by a ports specification: +.IP "\(bu" 4 +{\fBeq|neq|gt|lt\fR} \fIport\fR +.IP "\(bu" 4 +\&\fBrange\fR \fIfrom\fR \fIto\fR .PP -.I flags -may be one of: -.RS -.HP -.RB { match\-any | match\-all } -.RB { + | - }{ fin | syn | rst | psh | ack | urg } -\&... -.br -Match packets with any or all of the tcp flags set -.RB ( + ) -or clear -.RB ( - ). -.HP -.B established -.br -Match "established" TCP connections: packets with -.B RST -or -.B ACK -set, and -.B SYN -clear. -.HP -.B fragments -.br -Match IP fragments. May not be specified on rules with layer 4 -matches. -.RE -.SH SEE ALSO -.BR l2tpns (8) +\&\fIflags\fR may be one of: +.IP "{\fBmatch\-any|match\-all\fR} {\fB+|\-\fR}{\fBfin|syn|rst|psh|ack|urg\fR} ..." 4 +.IX Item "{match-any|match-all} {+|-}{fin|syn|rst|psh|ack|urg} ..." +Match packets with any or all of the tcp flags set (+) or clear (\-). +.IP "\fBestablished\fR" 4 +.IX Item "established" +Match \*(L"established\*(R" \s-1TCP\s0 connections: packets with \s-1RST\s0 or \s-1ACK\s0 set, and \s-1SYN\s0 clear. +.IP "\fBfragments\fR" 4 +.IX Item "fragments" +Match \s-1IP\s0 fragments. May not be specified on rules with layer 4 matches. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fIl2tpns\fR\|(8) diff --git a/Docs/startup-config.5.pod b/Docs/startup-config.5.pod new file mode 100644 index 0000000..93a3700 --- /dev/null +++ b/Docs/startup-config.5.pod @@ -0,0 +1,493 @@ +=pod + +=head1 NAME + +startup-config - configuration file for l2tpns + +=head1 SYNOPSIS + +/etc/l2tpns/startup-config + +=head1 DESCRIPTION + +B is the configuration file for B + +The format is plain text, in the same format as accepted by +the configuration mode of l2tpns's telnet administrative +interface. Comments are indicated by either the character # or !. + +=head2 SETTINGS + +Settings are specified with + +=over + +=item B F F + +=back + +A list of the possible configuration directives follows. Each of these should be set by a line like: + +=over + +=item B I I<"value"> + +=item B I I<192.168.1.1> + +=item B I I + +=back + +The following F may be set: + +=over + +=item B (string) + +If set to a directory, then every 5 minutes the current usage for every connected use will be dumped to a file in this directory. Each file dumped begins with a header, where each line is prefixed by #. Following the header is a single line for every connected user, fields separated by a space. + +The fields are username, ip, qos, uptxoctets, downrxoctets, origin (optional). The qos field is 1 if a standard user, and 2 if the user is throttled. The origin field is dump if B is set to true (origin value: L=LAC data, R=Remote LNS data, P=PPPOE data). + +=item B (boolean) + +If set to true, all origin of the usage is dumped to the accounting file (LAC+Remote LNS+PPPOE)(default false). + +=item B (boolean) + +Allow multiple logins with the same username. If false (the default), any prior session with the same username will be dropped when a new session is established. + +=item B (boolean) + +This parameter authorize to change the source IP of the tunnels l2tp. This parameter can be used when the remotes BAS/LAC are l2tpns server configured in cluster mode, but that the interface to remote LNS are not clustered (the tunnel can be coming from different source IP) (default: no). + +=item B (ip address) + +It's the listen address of the l2tp udp protocol sent and received to LAC. This address is also assigned to the tun interface if no iftun_address is specified. Packets containing user traffic should be routed via this address if given, otherwise the primary address of the machine. + +=item B (ip address) + +This parameter permit to listen several addresss of the l2tp udp protocol (and set several address to the tun interface). + +WHEN this parameter is set, It OVERWRITE the parameters "bind_address" and "iftun_address". + +these can be interesting when you want do load-balancing in cluster mode of the uploaded from the LAC. For example you can set a bgp.prepend(MY_AS) for Address1 on LNS1 and a bgp.prepend(MY_AS) for Address2 on LNS2 (see BGP AS-path prepending). + +example of use with 2 address: + +B I "64.14.13.41, 64.14.13.42" + +=item B (ip address) + +Multicast cluster address (default: 239.192.13.13). See the section on Clustering for more information. + +=item B (string) + +Interface for cluster packets (default: eth0). + +=item B (int) + +TTL for multicast packets (default: 1). + +=item B (int) + +Interval in tenths of a second between cluster heartbeat/pings. + +=item B (int) + +Cluster heartbeat timeout in tenths of a second. A new master will be elected when this interval has been passed without seeing a heartbeat from the master. + +=item B (int) + +Determines the minumum number of up to date slaves required before the master will drop routes (default: 1). + +=item B (int) + +Set the level of debugging messages written to the log file. The value should +be between 0 and 5, with 0 being no debugging, and 5 being the highest. +A rough description of the levels is: + +=over + +=item 0. Critical Errors - Things are probably broken + +=item 1. Errors - Things might have gone wrong, but probably will recover + +=item 2. Warnings - Just in case you care what is not quite perfect + +=item 3. Information - Parameters of control packets + +=item 4. Calls - For tracing the execution of the code + +=item 5. Packets - Everything, including a hex dump of all packets processed... probably twice + +=back + +Note that the higher you set the debugging level, the slower the program will run. Also, at level 5 a LOT of information will be logged. This should only ever be used for working out why it doesn't work at all. + +=item B (boolean) + +If set to true, then the current bandwidth utilization will be logged every second. Even if this is disabled, you can see this information by running the uptime command on the CLI. + +=item B (boolean) + +Disable l2tp sending HELLO message for Apple compatibility. Some OS X implementation of l2tp no manage the L2TP "HELLO message". (default: no). + +=item B (int) + +Time between last packet sent and LCP ECHO generation (default: 10 (seconds)). + +=item B + +Allow multiple logins matching this specific username. + +=item B (int) + +Maximum number of host unreachable ICMP packets to send per second. + +=item B (int) + +Drop sessions who have not responded within idle_echo_timeout seconds (default: 240 (seconds)) + +=item B (ip address) + +This parameter is used when you want a tun interface address different from the address of "bind_address" (For use in cases of specific configuration). If no address is given to iftun_address and bind_address, 1.1.1.1 is used. + +=item B (int) + +MTU of interface for L2TP traffic (default: 1500). Used to set link MRU and adjust TCP MSS. + +=item B (string) + +The secret used by l2tpns for authenticating tunnel request. Must be the same as the LAC, or authentication will fail. Only actually be used if the LAC requests authentication. + +=item B (boolean) + +Keep all pages mapped by the l2tpns process in memory. + +=item B (string) + +This will be where all logging and debugging information is written to.This may be either a filename, such as /var/log/l2tpns, or the string syslog:facility, where facility is any one of the syslog logging facilities, such as local5. + +=item B (int) + +Number of packets to read off each of the UDP and TUN fds when returned as readable by select (default: 10). Avoids incurring the unnecessary system call overhead of select on busy servers. + +=item B (int> + +Maximum number of packets of downstream traffic to be handled each tenth of a second per session. If zero, no limit is applied (default: 0). Intended as a DoS prevention mechanism and not a general throttling control (packets are dropped, not queued). + +=item B (ip address) + +Address to send to clients as the default gateway. + +=item B (string) + +If set, the process id will be written to the specified file. The value must be an absolute path. + +=item B (int) + +=item B (int) + +=item B (int) + +PPP counter and timer values, as described in Section 4.1 of RFC1661. + +I, Restart timer for PPP protocol negotiation in seconds (default: 3). + +I, Number of configure requests to send before giving up (default: 10). + +I, Number of Configure-Nak requests to send before sending a Configure-Reject (default: 5). + +=item B (ip address), B (ip address) + +Whenever a PPP connection is established, DNS servers will be sent to the user, both a primary and a secondary. If either is set to 0.0.0.0, then that one will not be sent. + +=item B (ip address), B (ip address) + +Sets the RADIUS servers used for both authentication and accounting. If the primary server does not respond, then the secondary RADIUS server will be tried. + +Note: in addition to the source IP address and identifier, the RADIUS server must include the source port when detecting duplicates to supress (in order to cope with a large number of sessions comming on-line simultaneously l2tpns uses a set of udp sockets, each with a seperate identifier). + +=item B (short), B (short) + +Sets the authentication ports for the primary and secondary RADIUS servers. The accounting port is one more than the authentication port. If no RADIUS ports are given, the authentication port defaults to 1645, and the accounting port to 1646. + +=item B (boolean) + +If set to true, then RADIUS accounting packets will be sent. This means that a B record will be sent when the session is successfully authenticated, and a B record will be sent when the session is closed. + +=item B (int) + +If radius_accounting is on, defines the interval between sending of RADIUS interim accounting records (in seconds). + +=item B (string) + +This secret will be used in all RADIUS queries. If this is not set then RADIUS queries will fail. + +=item B (string) + +A comma separated list of supported RADIUS authentication methods ("pap" or "chap"), in order of preference (default "pap"). + +=item B (short) + +Port for DAE RADIUS (Packet of Death/Disconnect, Change of Authorization) requests (default: 3799). + +=item B, B (int) + +Define a port range in which to bind sockets used to send and receive RADIUS packets. Must be at least RADIUS_FDS (64) wide. Simplifies firewalling of RADIUS ports (default: dynamically assigned). + +=item B (string) + +Path to random data source (default /dev/urandom). Use "" to use the rand() library function. + +=item B (boolean) + +Sets the scheduling policy for the l2tpns process to SCHED_FIFO. This causes the kernel to immediately preempt any currently running SCHED_OTHER (normal) process in favour of l2tpns when it becomes runnable. Ignored on uniprocessor systems. + +=item B (boolean) + +Determines whether or not to send a gratuitous ARP for the bind_address when the server is ready to handle traffic (default: true). This value is ignored if BGP is configured. + +=item B (string) + +Name of the tun interface (default: "tun0"). + +=item B (int) + +Sets the default speed (in kbits/s) which sessions will be limited to. If this is set to 0, then throttling will not be used at all. Note: You can set this by the CLI, but changes will not affect currently connected users. + +=item B (int) + +Number of token buckets to allocate for throttling. Each throttled session requires two buckets (in and out). + +=back + +=head2 DHCPv6 And IPv6 SETTINGS + +=over + +=item B (int) + +The preferred lifetime for the IPv6 address and the IPv6 prefix address, expressed in units of seconds (see rfc3315). + +=item B (int) + +The valid lifetime for the IPv6 address and the IPv6 prefix address, expressed in units of seconds (see rfc3315). + +=item B (int) + +DUID Based on Link-layer Address (DUID-LL) (see rfc3315). + +=item B, B (Ipv6 address) + +IPv6 DNS servers will be sent to the user (see rfc3646). + +=item B (string) + +The Domain Search List (ex: "fdn.fr") (see rfc3646). + +=item B (Ipv6 address) + +Enable negotiation of IPv6. This forms the the first 64 bits of the client allocated address. The remaining 64 come from the allocated IPv4 address and 4 bytes of 0. + +=back + +=head2 LAC SETTINGS + +=over + +=item B (ip address) + +Address of the interface to listen the remote LNS tunnels. If no address is given, all interfaces are listened (Any Address). + +=item B (short) + +Port to bind for the Remote LNS (default: 65432). + +=back + +A static REMOTES LNS configuration can be entered by the command: + +=over + +=item B I I I I + +where MASK specifies the mask of users who have forwarded to remote LNS (ex: "/friendISP@company.com"). + +where IP specifies the IP of the remote LNS (ex: "66.66.66.55"). + +where PORT specifies the L2TP Port of the remote LNS (Normally should be 1701) (ex: 1701). + +where SECRET specifies the secret password the remote LNS (ex: mysecret). + +=back + +The static REMOTE LNS configuration can be used when the friend ISP not have a proxied Radius. + +If a proxied Radius is used, It will return the RADIUS attributes: + +=over + +=item Tunnel-Type:1 = L2TP + +=item Tunnel-Medium-Type:1 = IPv4 + +=item Tunnel-Password:1 = "LESECRETL2TP" + +=item Tunnel-Server-Endpoint:1 = "88.xx.xx.x1" + +=item Tunnel-Assignment-Id:1 = "friendisp_lns1" + +=item Tunnel-Type:2 += L2TP + +=item Tunnel-Medium-Type:2 += IPv4 + +=item Tunnel-Password:2 += "LESECRETL2TP" + +=item Tunnel-Server-Endpoint:2 += "88.xx.xx.x2" + +=item Tunnel-Assignment-Id:2 += "friendisp_lns2" + +=back + +=head2 PPPOE SETTINGS + +=over + +=item B (string) + +PPPOE server interface to bind (ex: "eth0.12"), If not specified the server PPPOE is not enabled. For the pppoe clustering, all the interfaces PPPOE of the clusters must use the same HW address (MAC address). + +=item B (string) + +PPPOE service name (default: NULL). + +=item B (string) + +PPPOE access concentrator name (default: "l2tpns-pppoe"). + +=item B (boolean) + +If set to yes, the PPPOE server only accepts clients with a "service-name" different from NULL and a "service-name" equal to server "service-name" (default: no). + +=back + +=head2 BGP ROUTING + +The routing configuration section is entered by the command + +B B I + +where I specifies the local AS number. + +Subsequent lines prefixed with B I define the attributes of BGP neighhbours. Valid commands are: + +B I B I + +B I B I I + +Where I specifies the BGP neighbour as either a hostname or IP address, I is the remote AS number and I, I are the timer values in seconds. + +=head2 NAMED ACCESS LISTS + +Named access lists may be defined with either of + +=over + +=item + +B B B I + +=item + +B B B I + +=back + +Subsequent lines starting with permit or deny define the body of the access-list. + +=head3 Standard Access Lists + +Standard access lists are defined with: + +=over + +=item + +{B|B} I [I] + +=back + +Where I and I specify IP matches using one of: + +=over + +=item + +I
    I + +=item + +B I
    + +=item + +B + +=back + +I
    and I are in dotted-quad notation, bits in the I indicate which address bits in I
    are relevant to the match (0 = exact match; 1 = don't care). + +The shorthand 'host address' is equivalent to 'I
    B<0.0.0.0>'; 'B' to 'B<0.0.0.0> B<255.255.255.255>'. + +=head3 Extended Access Lists + +Extended access lists are defined with: + +=over + +=item + +{B|B} I I [I] I [I] [I] + +=back + +Where I is one of B, B or B, and I and I are as described above for standard lists. + +For TCP and UDP matches, source and destination may be optionally followed by a ports specification: + +=over + +=item + +{B} I + +=item + +B I I + +=back + +I may be one of: + +=over + +=item {B} {B<+|->}{B} ... + +Match packets with any or all of the tcp flags set (+) or clear (-). + +=item B + +Match "established" TCP connections: packets with RST or ACK set, and SYN clear. + +=item B + +Match IP fragments. May not be specified on rules with layer 4 matches. + +=back + +=head1 SEE ALSO + +L + +=cut diff --git a/Makefile b/Makefile index fb12741..36789e3 100644 --- a/Makefile +++ b/Makefile @@ -26,7 +26,7 @@ INSTALL = install -c -D -o root -g root l2tpns.LIBS = -lcli -ldl OBJS = arp.o cli.o cluster.o constants.o control.o icmp.o l2tpns.o \ - ll.o md5.o ppp.o radius.o tbf.o util.o pppoe.o l2tplac.o + ll.o md5.o ppp.o radius.o tbf.o util.o pppoe.o l2tplac.o dhcp6.o ipv6_u.o PROGRAMS = l2tpns nsctl PLUGINS = autosnoop.so autothrottle.so garden.so sessionctl.so \ @@ -108,31 +108,35 @@ install: all .PHONY: all clean depend install ## Dependencies: (autogenerated) ## -arp.o: arp.c l2tpns.h -cli.o: cli.c l2tpns.h constants.h util.h cluster.h tbf.h ll.h bgp.h \ - l2tplac.h -cluster.o: cluster.c l2tpns.h cluster.h util.h tbf.h pppoe.h bgp.h +arp.o: arp.c dhcp6.h l2tpns.h +cli.o: cli.c dhcp6.h l2tpns.h constants.h util.h cluster.h tbf.h ll.h \ + bgp.h l2tplac.h +cluster.o: cluster.c dhcp6.h l2tpns.h cluster.h util.h tbf.h pppoe.h \ + bgp.h constants.o: constants.c constants.h -control.o: control.c l2tpns.h control.h -icmp.o: icmp.c l2tpns.h pppoe.h -l2tpns.o: l2tpns.c md5.h l2tpns.h cluster.h plugin.h ll.h constants.h \ - control.h util.h tbf.h bgp.h l2tplac.h pppoe.h +control.o: control.c dhcp6.h l2tpns.h control.h +icmp.o: icmp.c dhcp6.h l2tpns.h ipv6_u.h +l2tpns.o: l2tpns.c md5.h dhcp6.h l2tpns.h cluster.h plugin.h ll.h \ + constants.h control.h util.h tbf.h bgp.h l2tplac.h pppoe.h ll.o: ll.c ll.h md5.o: md5.c md5.h -ppp.o: ppp.c l2tpns.h constants.h plugin.h util.h tbf.h cluster.h \ +ppp.o: ppp.c dhcp6.h l2tpns.h constants.h plugin.h util.h tbf.h cluster.h \ l2tplac.h pppoe.h -radius.o: radius.c md5.h constants.h l2tpns.h plugin.h util.h cluster.h \ - l2tplac.h pppoe.h -tbf.o: tbf.c l2tpns.h util.h tbf.h -util.o: util.c l2tpns.h bgp.h -pppoe.o: pppoe.c l2tpns.h cluster.h constants.h md5.h util.h -l2tplac.o: l2tplac.c md5.h l2tpns.h util.h cluster.h l2tplac.h pppoe.h -bgp.o: bgp.c l2tpns.h bgp.h util.h -autosnoop.so: autosnoop.c l2tpns.h plugin.h -autothrottle.so: autothrottle.c l2tpns.h plugin.h -garden.so: garden.c l2tpns.h plugin.h control.h -sessionctl.so: sessionctl.c l2tpns.h plugin.h control.h -setrxspeed.so: setrxspeed.c l2tpns.h plugin.h -snoopctl.so: snoopctl.c l2tpns.h plugin.h control.h -stripdomain.so: stripdomain.c l2tpns.h plugin.h -throttlectl.so: throttlectl.c l2tpns.h plugin.h control.h +radius.o: radius.c md5.h constants.h dhcp6.h l2tpns.h plugin.h util.h \ + cluster.h l2tplac.h pppoe.h +tbf.o: tbf.c dhcp6.h l2tpns.h util.h tbf.h +util.o: util.c dhcp6.h l2tpns.h bgp.h +pppoe.o: pppoe.c dhcp6.h l2tpns.h cluster.h constants.h md5.h util.h +l2tplac.o: l2tplac.c md5.h dhcp6.h l2tpns.h util.h cluster.h l2tplac.h \ + pppoe.h +dhcp6.o: dhcp6.c dhcp6.h l2tpns.h ipv6_u.h +ipv6_u.o: ipv6_u.c ipv6_u.h +bgp.o: bgp.c dhcp6.h l2tpns.h bgp.h util.h +autosnoop.so: autosnoop.c dhcp6.h l2tpns.h plugin.h +autothrottle.so: autothrottle.c dhcp6.h l2tpns.h plugin.h +garden.so: garden.c dhcp6.h l2tpns.h plugin.h control.h +sessionctl.so: sessionctl.c dhcp6.h l2tpns.h plugin.h control.h +setrxspeed.so: setrxspeed.c dhcp6.h l2tpns.h plugin.h +snoopctl.so: snoopctl.c dhcp6.h l2tpns.h plugin.h control.h +stripdomain.so: stripdomain.c dhcp6.h l2tpns.h plugin.h +throttlectl.so: throttlectl.c dhcp6.h l2tpns.h plugin.h control.h diff --git a/arp.c b/arp.c index 6d55756..0aae069 100644 --- a/arp.c +++ b/arp.c @@ -5,7 +5,9 @@ #include #include #include +#include +#include "dhcp6.h" #include "l2tpns.h" /* Most of this code is based on keepalived:vrrp_arp.c */ diff --git a/autosnoop.c b/autosnoop.c index ddc699f..c520aaf 100644 --- a/autosnoop.c +++ b/autosnoop.c @@ -1,4 +1,6 @@ #include +#include +#include "dhcp6.h" #include "l2tpns.h" #include "plugin.h" diff --git a/autothrottle.c b/autothrottle.c index 73f9a94..9d55456 100644 --- a/autothrottle.c +++ b/autothrottle.c @@ -1,4 +1,6 @@ #include +#include +#include "dhcp6.h" #include "l2tpns.h" #include "plugin.h" diff --git a/bgp.c b/bgp.c index 7c1e6c0..2791ca3 100644 --- a/bgp.c +++ b/bgp.c @@ -21,6 +21,7 @@ #include #include +#include "dhcp6.h" #include "l2tpns.h" #include "bgp.h" #include "util.h" diff --git a/cli.c b/cli.c index f280330..e63d73e 100644 --- a/cli.c +++ b/cli.c @@ -22,6 +22,7 @@ #include #include +#include "dhcp6.h" #include "l2tpns.h" #include "constants.h" #include "util.h" diff --git a/cluster.c b/cluster.c index 94d0cd0..12f9d58 100644 --- a/cluster.c +++ b/cluster.c @@ -17,6 +17,7 @@ #include #include +#include "dhcp6.h" #include "l2tpns.h" #include "cluster.h" #include "util.h" @@ -842,7 +843,7 @@ static int hb_add_type(uint8_t **p, int type, int id) // Failed to compress : Fall through. } case C_SESSION: - add_type(p, C_SESSION, id, (uint8_t *) &session[id], sizeof(sessiont)); + add_type(p, C_SESSION, id, (uint8_t *) &session[id], sizeof(sessiont)); break; case C_CBUNDLE: { // Compressed C_BUNDLE @@ -883,7 +884,7 @@ static int hb_add_type(uint8_t **p, int type, int id) // Failed to compress : Fall through. } case C_TUNNEL: - add_type(p, C_TUNNEL, id, (uint8_t *) &tunnel[id], sizeof(tunnelt)); + add_type(p, C_TUNNEL, id, (uint8_t *) &tunnel[id], sizeof(tunnelt)); break; default: LOG(0, 0, 0, "Found an invalid type in heart queue! (%d)\n", type); @@ -1504,11 +1505,11 @@ static int cluster_process_heartbeat(uint8_t *data, int size, int more, uint8_t int i, type; int hb_ver = more; -#if HB_VERSION != 7 +#if HB_VERSION != 8 # error "need to update cluster_process_heartbeat()" #endif - // we handle versions 5 through 7 + // we handle versions 5 through 8 if (hb_ver < 5 || hb_ver > HB_VERSION) { LOG(0, 0, 0, "Received a heartbeat version that I don't support (%d)!\n", hb_ver); return -1; // Ignore it?? @@ -1681,10 +1682,18 @@ static int cluster_process_heartbeat(uint8_t *data, int size, int more, uint8_t break; } - if (size != sizeof(sessiont) ) { // Ouch! Very very bad! - LOG(0, 0, 0, "DANGER: Received a CSESSION that didn't decompress correctly!\n"); - // Now what? Should exit! No-longer up to date! - break; + if (size != sizeof(sessiont)) { // Ouch! Very very bad! + if ((hb_ver < HB_VERSION) && (size < sizeof(sessiont))) + { + LOG(2, 0, 0, "WARNING: Received a CSESSION from %s hb_version %d != %d current version !\n", fmtaddr(addr, 2), hb_ver, HB_VERSION); + // New feature not activated until the master has not been upgraded. + } + else + { + LOG(0, 0, 0, "DANGER: Received a CSESSION that didn't decompress correctly!\n"); + // Now what? Should exit! No-longer up to date! + break; + } } cluster_recv_session(more, c); diff --git a/cluster.h b/cluster.h index bb7ca5a..b7a91f1 100644 --- a/cluster.h +++ b/cluster.h @@ -26,7 +26,7 @@ #define C_MPPP_FORWARD 19 // MPPP Forwarded packet.. #define C_PPPOE_FORWARD 20 // PPPOE Forwarded packet.. -#define HB_VERSION 7 // Protocol version number.. +#define HB_VERSION 8 // Protocol version number.. #define HB_MAX_SEQ (1<<30) // Maximum sequence number. (MUST BE A POWER OF 2!) #define HB_HISTORY_SIZE 64 // How many old heartbeats we remember?? (Must be a factor of HB_MAX_SEQ) diff --git a/control.c b/control.c index 3d38b22..1ccd07a 100644 --- a/control.c +++ b/control.c @@ -1,6 +1,8 @@ // L2TPNS: control #include +#include +#include "dhcp6.h" #include "l2tpns.h" #include "control.h" diff --git a/debian/changelog b/debian/changelog index 5dc13f3..b55dadd 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,10 @@ -l2tpns (2.2.1-2fdn3.12) UNRELEASED; urgency=low +l2tpns (2.2.1-2fdn3.13) unstable; urgency=low + + * Add DHCPv6 functionality + + -- Fernando Alves Thu, 11 Sep 2014 16:10:38 +0200 + +l2tpns (2.2.1-2fdn3.12) unstable; urgency=low * Fix: remove old IPV6 routes on master diff --git a/debian/control b/debian/control index b60e24f..979899e 100644 --- a/debian/control +++ b/debian/control @@ -16,5 +16,5 @@ Description: layer 2 tunnelling protocol network server (LNS) limiting, walled garden, usage accounting, and clustering (for both load-sharing and redundancy). . - Note that only the LNS side of the L2TP protocol is implemented, for - a more complete L2TP implementation see the l2tpd package. + l2tpns is a complete L2TP implementation. It supports the LAC, LNS, + PPPOE and DHCPv6 server. diff --git a/dhcp6.c b/dhcp6.c new file mode 100644 index 0000000..e422df5 --- /dev/null +++ b/dhcp6.c @@ -0,0 +1,544 @@ +/* + * Fernando ALVES 2014 + * Add functionality DHCPv6 to l2tpns. + * GPL licenced + */ + +#include +#include +#include + +#include "dhcp6.h" +#include "l2tpns.h" +#include "ipv6_u.h" + +struct dhcp6_in_option +{ + struct dhcp6_mess_hdr *p_mess_hdr; + struct dhcp6_opt_h *p_opt_clientid; + struct dhcp6_opt_h *p_opt_serverid; + struct dhcp6_opt_h *p_opt_ia_na; + struct dhcp6_opt_h *p_opt_ia_ta; + struct dhcp6_opt_h *p_opt_ia_pd; + struct dhcp6_opt_h *p_opt_oro; + struct dhcp6_opt_h *p_opt_rapidcommit; +}; + +static struct dhcp6_opt_serverid dhcp6_local_serverid; +static struct dhcp6_in_option list_option; + +static int dhcpv6_format_dns_search_name(const char *strdns, uint8_t *buffer); + +static void dhcp6_send_reply(sessionidt s, tunnelidt t, struct in6_addr *ip6_src) +{ + struct ip6_hdr *p_ip6_hdr; + struct udphdr *p_udp; + struct dhcp6_mess_hdr *p_mess_hdr; + struct dhcp6_opt_h *p_opt; + struct ipv6_pseudo_hdr pseudo_hdr; + uint8_t b[MAXETHER + 20]; + int len; + + memset(b, 0, sizeof(b)); + p_ip6_hdr = (struct ip6_hdr *) makeppp(b, sizeof(b), 0, 0, s, t, PPPIPV6, 0, 0, 0); + + // IPv6 Header + p_ip6_hdr->ip6_vfc = 0x60; // IPv6 + p_ip6_hdr->ip6_plen = 0; // Length of payload (not header) (calculation below) + p_ip6_hdr->ip6_nxt = IPPROTO_UDP; // icmp6 is next + p_ip6_hdr->ip6_hlim = 1; // Hop limit + // IPv6 Src FE02::1:2 + inet_pton(AF_INET6, "FE02::1:2", &p_ip6_hdr->ip6_src.s6_addr); + // IPv6 Dest + memcpy(&p_ip6_hdr->ip6_dst.s6_addr, ip6_src, sizeof(p_ip6_hdr->ip6_dst.s6_addr)); + + // UDP Header + p_udp = (struct udphdr *) &p_ip6_hdr[1]; + p_udp->source = htons(547); + p_udp->dest = htons(546); + p_udp->len = 0; // Length udp size_udp_header + data (calculation below) + p_udp->check = 0; // checksum (calculation below with ip pseudo header) + + // DHCPv6 msg header + p_mess_hdr = (struct dhcp6_mess_hdr *) &p_udp[1]; + if (list_option.p_mess_hdr->type == DHCP6_SOLICIT) + p_mess_hdr->type = list_option.p_opt_rapidcommit ? DHCP6_REPLY : DHCP6_ADVERTISE; + else + p_mess_hdr->type = DHCP6_REPLY; + + p_mess_hdr->trans_id = list_option.p_mess_hdr->trans_id; + + // DHCPv6 options header + p_opt = (struct dhcp6_opt_h *) &p_mess_hdr[1]; + memcpy(p_opt, &dhcp6_local_serverid, ntohs(dhcp6_local_serverid.opt_hdr.len) + sizeof(dhcp6_local_serverid.opt_hdr)); // ServerID + p_opt = (struct dhcp6_opt_h *) (((uint8_t *) p_opt) + ntohs(p_opt->len) + sizeof(*p_opt)); // next option + + if (list_option.p_opt_clientid) + { + memcpy(p_opt, list_option.p_opt_clientid, ntohs(list_option.p_opt_clientid->len) + sizeof(*p_opt)); // ClientID + p_opt = (struct dhcp6_opt_h *) (((uint8_t *) p_opt) + ntohs(p_opt->len) + sizeof(*p_opt)); // next option + } + + if (list_option.p_opt_ia_pd && (list_option.p_mess_hdr->type != DHCP6_INFORMATION_REQUEST)) + { + p_opt->code = htons(D6_OPT_IA_PD); // D6_OPT_IA_PD + ((struct dhcp6_opt_ia_pd *)p_opt)->iaid = ((struct dhcp6_opt_ia_pd *)list_option.p_opt_ia_pd)->iaid; + ((struct dhcp6_opt_ia_pd *)p_opt)->T1 = (config->dhcp6_preferred_lifetime > 0) ? htonl(config->dhcp6_preferred_lifetime/2) : 0xFFFFFFFF; + ((struct dhcp6_opt_ia_pd *)p_opt)->T2 = (config->dhcp6_preferred_lifetime > 0) ? htonl((config->dhcp6_preferred_lifetime*4)/5) : 0xFFFFFFFF; + + if ((list_option.p_mess_hdr->type == DHCP6_RENEW) && session[s].dhcpv6_prefix_iaid != ((struct dhcp6_opt_ia_pd *)list_option.p_opt_ia_pd)->iaid) + { + p_opt->len = htons(sizeof(struct dhcp6_opt_ia_pd) - sizeof(*p_opt) + sizeof(struct dhcp6_opt_status)); + p_opt = (struct dhcp6_opt_h *) &((struct dhcp6_opt_ia_pd *)p_opt)[1]; + + ((struct dhcp6_opt_status *)p_opt)->hdr.code = htons(D6_OPT_STATUS_CODE); + ((struct dhcp6_opt_status *)p_opt)->hdr.len = htons(2); + ((struct dhcp6_opt_status *)p_opt)->code = htons(D6_STATUS_NoBinding); + p_opt = (struct dhcp6_opt_h *) &((struct dhcp6_opt_status *)p_opt)[1]; // next option + } + else + { + if (list_option.p_mess_hdr->type == DHCP6_REQUEST || list_option.p_opt_rapidcommit) + { + session[s].dhcpv6_prefix_iaid = ((struct dhcp6_opt_ia_pd *)list_option.p_opt_ia_pd)->iaid; + } + + p_opt->len = htons(sizeof(struct dhcp6_opt_ia_pd) - sizeof(*p_opt) + sizeof(struct dhcp6_opt_ia_prefix)); + p_opt = (struct dhcp6_opt_h *) &((struct dhcp6_opt_ia_pd *)p_opt)[1]; + + ((struct dhcp6_opt_ia_prefix *)p_opt)->hdr.code = htons(D6_OPT_IAPREFIX); + ((struct dhcp6_opt_ia_prefix *)p_opt)->hdr.len = htons(sizeof(struct dhcp6_opt_ia_prefix) - sizeof(*p_opt)); + ((struct dhcp6_opt_ia_prefix *)p_opt)->pref_lifetime= (config->dhcp6_preferred_lifetime > 0) ? htonl(config->dhcp6_preferred_lifetime) : 0xFFFFFFFF; + ((struct dhcp6_opt_ia_prefix *)p_opt)->valid_lifetime= (config->dhcp6_valid_lifetime > 0) ? htonl(config->dhcp6_valid_lifetime) : 0xFFFFFFFF; + ((struct dhcp6_opt_ia_prefix *)p_opt)->prefix_len = session[s].ipv6prefixlen; + ((struct dhcp6_opt_ia_prefix *)p_opt)->prefix = session[s].ipv6route; + p_opt = (struct dhcp6_opt_h *) &((struct dhcp6_opt_ia_prefix *)p_opt)[1]; // next option + } + } + + if (list_option.p_opt_ia_na && (list_option.p_mess_hdr->type != DHCP6_INFORMATION_REQUEST)) + { + p_opt->code = htons(D6_OPT_IA_NA); // D6_OPT_IA_NA + ((struct dhcp6_opt_ia_na *)p_opt)->iaid = ((struct dhcp6_opt_ia_na *)list_option.p_opt_ia_na)->iaid; + ((struct dhcp6_opt_ia_na *)p_opt)->T1 = (config->dhcp6_preferred_lifetime > 0) ? htonl(config->dhcp6_preferred_lifetime/2) : 0xFFFFFFFF; + ((struct dhcp6_opt_ia_na *)p_opt)->T2 = (config->dhcp6_preferred_lifetime > 0) ? htonl((config->dhcp6_preferred_lifetime*4)/5) : 0xFFFFFFFF; + + if ((list_option.p_mess_hdr->type == DHCP6_RENEW) && session[s].dhcpv6_iana_iaid != ((struct dhcp6_opt_ia_na *)list_option.p_opt_ia_na)->iaid) + { + p_opt->len = htons(sizeof(struct dhcp6_opt_ia_na) - sizeof(*p_opt) + sizeof(struct dhcp6_opt_status)); + p_opt = (struct dhcp6_opt_h *) &((struct dhcp6_opt_ia_na *)p_opt)[1]; + + ((struct dhcp6_opt_status *)p_opt)->hdr.code = htons(D6_OPT_STATUS_CODE); + ((struct dhcp6_opt_status *)p_opt)->hdr.len = htons(2); + ((struct dhcp6_opt_status *)p_opt)->code = htons(D6_STATUS_NoBinding); + p_opt = (struct dhcp6_opt_h *) &((struct dhcp6_opt_status *)p_opt)[1]; // next option + } + else + { + in_addr_t addr_ipv4; + + if (list_option.p_mess_hdr->type == DHCP6_REQUEST || list_option.p_opt_rapidcommit) + { + session[s].dhcpv6_iana_iaid = ((struct dhcp6_opt_ia_na *)list_option.p_opt_ia_na)->iaid; + } + + p_opt->len = htons(sizeof(struct dhcp6_opt_ia_na) - sizeof(*p_opt) + sizeof(struct dhcp6_opt_ia_addr)); + p_opt = (struct dhcp6_opt_h *) &((struct dhcp6_opt_ia_na *)p_opt)[1]; + + ((struct dhcp6_opt_ia_addr *)p_opt)->hdr.code = htons(D6_OPT_IAADDR); + ((struct dhcp6_opt_ia_addr *)p_opt)->hdr.len = htons(sizeof(struct dhcp6_opt_ia_addr) - sizeof(*p_opt)); + + if (session[s].ipv6address.s6_addr[0]) + { + memcpy(&((struct dhcp6_opt_ia_addr *)p_opt)->addr, &session[s].ipv6address, 16); // copy ipv6 prefix + } + else + { + memcpy(&((struct dhcp6_opt_ia_addr *)p_opt)->addr, &config->ipv6_prefix, 8); // copy prefix 64 + addr_ipv4 = htonl(session[s].ip); + memcpy(&((struct dhcp6_opt_ia_addr *)p_opt)->addr.s6_addr[8], &addr_ipv4, 4); // copy ipv4 + } + + ((struct dhcp6_opt_ia_addr *)p_opt)->pref_lifetime= (config->dhcp6_preferred_lifetime > 0) ? htonl(config->dhcp6_preferred_lifetime) : 0xFFFFFFFF; + ((struct dhcp6_opt_ia_addr *)p_opt)->valid_lifetime= (config->dhcp6_valid_lifetime > 0) ? htonl(config->dhcp6_valid_lifetime) : 0xFFFFFFFF; + + p_opt = (struct dhcp6_opt_h *) &((struct dhcp6_opt_ia_addr *)p_opt)[1]; // next option + } + } + + if (list_option.p_opt_ia_ta && (list_option.p_mess_hdr->type != DHCP6_INFORMATION_REQUEST)) + { + p_opt->code = htons(D6_OPT_IA_TA); // D6_OPT_IA_TA + p_opt->len = htons(sizeof(struct dhcp6_opt_ia_ta) - sizeof(*p_opt) + sizeof(struct dhcp6_opt_status)); + ((struct dhcp6_opt_ia_ta *)p_opt)->iaid = ((struct dhcp6_opt_ia_ta *)list_option.p_opt_ia_ta)->iaid; + p_opt = (struct dhcp6_opt_h *) &((struct dhcp6_opt_ia_ta *)p_opt)[1]; + ((struct dhcp6_opt_status *)p_opt)->hdr.code = htons(D6_OPT_STATUS_CODE); + ((struct dhcp6_opt_status *)p_opt)->hdr.len = htons(2); + ((struct dhcp6_opt_status *)p_opt)->code = htons(D6_STATUS_UnspecFail); + p_opt = (struct dhcp6_opt_h *) &((struct dhcp6_opt_status *)p_opt)[1]; // next option + } + + if (list_option.p_opt_oro) + { + int countopt; + uint16_t *ptrw; + struct in6_addr *ptr_in6_addr; + + for (countopt = ntohs(list_option.p_opt_oro->len)/2, ptrw = (uint16_t *)((struct dhcp6_opt_oro *)list_option.p_opt_oro)->opt_demand; countopt; countopt--, ptrw++) + { + if (ntohs(*ptrw) == D6_OPT_DNS_SERVERS) + { + if (config->default_ipv6_dns1.s6_addr[0]) + { + p_opt->code = htons(D6_OPT_DNS_SERVERS); // D6_OPT_DNS_SERVERS + p_opt->len = htons(sizeof(*ptr_in6_addr)); + ptr_in6_addr = (struct in6_addr *) &p_opt[1]; + memcpy(ptr_in6_addr, &config->default_ipv6_dns1, sizeof(*ptr_in6_addr)); + + if (config->default_ipv6_dns2.s6_addr[0]) + { + p_opt->len = htons(2*sizeof(*ptr_in6_addr)); + ptr_in6_addr = &ptr_in6_addr[1]; + memcpy(ptr_in6_addr, &config->default_ipv6_dns2, sizeof(*ptr_in6_addr)); + } + + p_opt = (struct dhcp6_opt_h *) &ptr_in6_addr[1]; // next option + } + } + + if (ntohs(*ptrw) == D6_OPT_DOMAIN_LIST) + { + if (*config->default_ipv6_domain_list) + { + uint8_t buffer[255]; + int len = dhcpv6_format_dns_search_name(config->default_ipv6_domain_list, buffer); + + if (len > 0) + { + p_opt->code = htons(D6_OPT_DOMAIN_LIST); // D6_OPT_DOMAIN_LIST + p_opt->len = htons(len); + memcpy((char *)&p_opt[1], buffer, len); + + p_opt = (struct dhcp6_opt_h *) (((uint8_t *) &p_opt[1]) + len); // next option + } + } + } + } + } + + if (list_option.p_opt_rapidcommit && (list_option.p_mess_hdr->type == DHCP6_SOLICIT)) + { + p_opt->code = htons(D6_OPT_RAPID_COMMIT); // D6_OPT_RAPID_COMMIT + p_opt->len = 0; + p_opt = &p_opt[1]; // next option + } + + p_opt->code = htons(D6_OPT_PREFERENCE); // D6_OPT_PREFERENCE + p_opt->len = htons(1); + ((struct dhcp6_opt_preference *)p_opt)->pref = 255; + p_opt = (struct dhcp6_opt_h *) &((struct dhcp6_opt_preference *)p_opt)[1]; // next option + + // calculation of lenght + len = ((uint8_t *) p_opt) - ((uint8_t *) p_udp); + p_ip6_hdr->ip6_plen = p_udp->len = htons(len); + + /* Use pseudo hearder for checksum calculation */ + memset(&pseudo_hdr, 0, sizeof(pseudo_hdr)); + memcpy(&pseudo_hdr.src, &p_ip6_hdr->ip6_src, 16); + memcpy(&pseudo_hdr.dest, &p_ip6_hdr->ip6_dst, 16); + pseudo_hdr.ulp_length = htonl(len); // Lenght whitout Ipv6 header + pseudo_hdr.nexthdr = IPPROTO_UDP; + // Checksum is over the udp payload plus the pseudo header + p_udp->check = ipv6_checksum(&pseudo_hdr, (uint8_t *) p_udp, len); + + // Add ipv6 header to length + len += sizeof(*p_ip6_hdr); + LOG(3, s, t, "Send DHCPv6 message %s\n", (p_mess_hdr->type == DHCP6_REPLY) ? "REPLY" : "ADVERTISE"); + tunnelsend(b, len + (((uint8_t *) p_ip6_hdr)-b), t); // send it... +} + +void dhcpv6_process(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l) +{ + struct ip6_hdr *p_ip6_hdr_in; + struct dhcp6_mess_hdr *p_mess_hdr; + struct dhcp6_opt_h *p_opt; + uint8_t *p_end; + uint16_t len; + + CSTAT(dhcpv6_process); + + p_ip6_hdr_in = (struct ip6_hdr *) p; + p_mess_hdr = (struct dhcp6_mess_hdr *) (p + 48); + + LOG(3, s, t, "Got DHCPv6 message Type: %d\n", p_mess_hdr->type); + + if (!session[s].ipv6route.s6_addr[0] || !session[s].ipv6prefixlen) + return; + + p_opt = (struct dhcp6_opt_h *) &p_mess_hdr[1]; + p_end = ((uint8_t *)p_ip6_hdr_in) + ntohs(p_ip6_hdr_in->ip6_plen) + sizeof(*p_ip6_hdr_in); + memset(&list_option, 0, sizeof(list_option)); + list_option.p_mess_hdr = p_mess_hdr; + while (((uint8_t *)p_opt) < p_end) + { + switch(ntohs(p_opt->code)) + { + case D6_OPT_CLIENTID: + list_option.p_opt_clientid = p_opt; + LOG(3, s, t, "......Option D6_OPT_CLIENTID\n"); + break; + case D6_OPT_SERVERID: + list_option.p_opt_serverid = p_opt; + LOG(3, s, t, "......Option D6_OPT_SERVERID\n"); + break; + case D6_OPT_RAPID_COMMIT: + list_option.p_opt_rapidcommit = p_opt; + LOG(3, s, t, "......Option D6_OPT_RAPID_COMMIT\n"); + break; + case D6_OPT_IA_NA: + list_option.p_opt_ia_na = p_opt; + LOG(3, s, t, "......Option D6_OPT_IA_NA\n"); + break; + case D6_OPT_IA_TA: + list_option.p_opt_ia_ta = p_opt; + LOG(3, s, t, "......Option D6_OPT_IA_TA\n"); + break; + case D6_OPT_ORO: + list_option.p_opt_oro = p_opt; + LOG(3, s, t, "......Option D6_OPT_ORO\n"); + break; + case D6_OPT_IA_PD: + list_option.p_opt_ia_pd = p_opt; + LOG(3, s, t, "......Option D6_OPT_IA_PD\n"); + break; + case D6_OPT_ELAPSED_TIME: + LOG(3, s, t, "......Option D6_OPT_ELAPSED_TIME\n"); + break; + + default: + LOG(3, s, t, "......DHCPv6 option: %d\n", ntohs(p_opt->code)); + break; + } + p_opt = (struct dhcp6_opt_h *)(((uint8_t *) p_opt) + ntohs(p_opt->len) + sizeof(*p_opt)); + } + + switch(p_mess_hdr->type) + { + case DHCP6_SOLICIT: + { + LOG(3, s, t, "..(Type %d = Solicit)\n", p_mess_hdr->type); + + if (!list_option.p_opt_clientid) + { + LOG(3, s, t, "DHCPv6: error no Client-ID\n"); + return; + } + else if (list_option.p_opt_rapidcommit) + { + if (!session[s].dhcpv6_client_id.opt_hdr.len) + { + len = ntohs(list_option.p_opt_clientid->len); + + if ((len > 0) && (len <= sizeof(struct dhcp6_duid))) + { + memcpy(&session[s].dhcpv6_client_id, list_option.p_opt_clientid, sizeof(struct dhcp6_opt_h) + len); + } + else + { + LOG(3, s, t, "DHCPv6: Error malformed Client-ID option\n"); + return; + } + } + else if (session[s].dhcpv6_client_id.opt_hdr.len != list_option.p_opt_clientid->len || + memcmp(&session[s].dhcpv6_client_id, list_option.p_opt_clientid, sizeof(struct dhcp6_opt_h) + ntohs(list_option.p_opt_clientid->len))) + { + LOG(3, s, t, "DHCPv6: Error unmatched Client-ID option\n"); + return; + } + } + + if (list_option.p_opt_serverid) + { + LOG(3, s, t, "DHCPv6: Error unexpected Server-ID option on Solicit\n"); + return; + } + + dhcp6_send_reply(s, t, &p_ip6_hdr_in->ip6_src); + } + break; + + case DHCP6_REQUEST: + { + LOG(3, s, t, "..(Type %d = Request)\n", p_mess_hdr->type); + + if (!list_option.p_opt_clientid) + { + LOG(3, s, t, "DHCPv6: error no Client-ID\n"); + return; + } + + if (!list_option.p_opt_serverid) + { + LOG(3, s, t, "DHCPv6: error no Server-ID\n"); + return; + } + else if (dhcp6_local_serverid.opt_hdr.len != list_option.p_opt_serverid->len || + memcmp(&dhcp6_local_serverid, list_option.p_opt_serverid, sizeof(struct dhcp6_opt_h) + ntohs(list_option.p_opt_serverid->len))) + { + LOG(3, s, t, "DHCPv6: Error unmatched Server-ID option\n"); + return; + } + + if (!session[s].dhcpv6_client_id.opt_hdr.len) + { + len = ntohs(list_option.p_opt_clientid->len); + + if ((len > 0) && (len <= sizeof(struct dhcp6_duid))) + { + memcpy(&session[s].dhcpv6_client_id, list_option.p_opt_clientid, sizeof(struct dhcp6_opt_h) + len); + } + else + { + LOG(3, s, t, "DHCPv6: Error malformed Client-ID option\n"); + return; + } + } + else if ( session[s].dhcpv6_client_id.opt_hdr.len != list_option.p_opt_clientid->len || + memcmp(&session[s].dhcpv6_client_id, list_option.p_opt_clientid, sizeof(struct dhcp6_opt_h) + ntohs(list_option.p_opt_clientid->len))) + { + LOG(3, s, t, "DHCPv6: Error unmatched Client-ID option\n"); + return; + } + + dhcp6_send_reply(s, t, &p_ip6_hdr_in->ip6_src); + } + break; + + case DHCP6_RENEW: + { + LOG(3, s, t, "..(Type %d = Renew)\n", p_mess_hdr->type); + + if (!list_option.p_opt_clientid) + { + LOG(3, s, t, "DHCPv6: error no Client-ID\n"); + return; + } + else if ( session[s].dhcpv6_client_id.opt_hdr.len != list_option.p_opt_clientid->len || + memcmp(&session[s].dhcpv6_client_id, list_option.p_opt_clientid, sizeof(struct dhcp6_opt_h) + ntohs(list_option.p_opt_clientid->len))) + { + LOG(3, s, t, "DHCPv6: Error unmatched Client-ID option\n"); + return; + } + + if (!list_option.p_opt_serverid) + { + LOG(3, s, t, "DHCPv6: error no Server-ID\n"); + return; + } + else if (dhcp6_local_serverid.opt_hdr.len != list_option.p_opt_serverid->len || + memcmp(&dhcp6_local_serverid, list_option.p_opt_serverid, sizeof(struct dhcp6_opt_h) + ntohs(list_option.p_opt_serverid->len))) + { + LOG(3, s, t, "DHCPv6: Error unmatched Server-ID option\n"); + return; + } + + dhcp6_send_reply(s, t, &p_ip6_hdr_in->ip6_src); + } + break; + + case DHCP6_INFORMATION_REQUEST: + { + LOG(3, s, t, "..(Type %d = Information Request)\n", p_mess_hdr->type); + + if (!list_option.p_opt_clientid) + { + LOG(3, s, t, "DHCPv6: error no Client-ID\n"); + return; + } + + dhcp6_send_reply(s, t, &p_ip6_hdr_in->ip6_src); + } + break; + + case DHCP6_REBIND: + { + LOG(3, s, t, "..(Type %d = Rebind)\n", p_mess_hdr->type); + } + break; + + case DHCP6_RELEASE: + { + LOG(3, s, t, "..(Type %d = Release)\n", p_mess_hdr->type); + } + break; + + case DHCP6_DECLINE: + { + LOG(3, s, t, "..(Type %d = Decline)\n", p_mess_hdr->type); + } + break; + + default: + LOG(3, s, t, "Got unknown DHCPv6 Type: %d\n", *(p + 38)); + break; + } + + return; +} + +static int dhcpv6_format_dns_search_name(const char *strdns, uint8_t *buffer) +{ + int n = strlen(strdns); + const char *ptr; + + if (strdns[n - 1] == '.') n++; + else n += 2; + + if (n > 255) { + LOG(3, 0, 0, "DHCPv6: DNS search '%s' is too long\n", strdns); + return 0; + } + + while (1) + { + ptr = strchr(strdns, '.'); + + if (!ptr) ptr = strchr(strdns, 0); + + if (ptr - strdns > 63) + { + LOG(3, 0, 0, "DHCPv6: DNS search '%s' is invalid\n", strdns); + return 0; + } + + *buffer = ptr - strdns; + memcpy(buffer + 1, strdns, ptr - strdns); + buffer += 1 + (ptr - strdns); + strdns = ptr + 1; + + if (!*ptr || !*strdns) + { + *buffer = 0; + break; + } + } + + return n; +} + +void dhcpv6_init(void) +{ + uint32_t id; + + dhcp6_local_serverid.opt_hdr.code = htons(D6_OPT_SERVERID); + dhcp6_local_serverid.opt_hdr.len = htons(4 + sizeof(id)); + dhcp6_local_serverid.duid.type = htons(DUID_LL); + dhcp6_local_serverid.duid.u.ll.htype = htons(27); + + if (config->dhcp6_server_duid) + id = htobe32(config->dhcp6_server_duid); + else + id = htobe32(0xFDFDFAFA); + + memcpy(dhcp6_local_serverid.duid.u.ll.addr, &id, sizeof(id)); +} diff --git a/dhcp6.h b/dhcp6.h new file mode 100644 index 0000000..4b0eb19 --- /dev/null +++ b/dhcp6.h @@ -0,0 +1,218 @@ +/* + * Fernando ALVES 2014 + * Add functionality DHCPv6 to l2tpns. + * GPL licenced + */ + +#ifndef __DHCP6_H__ +#define __DHCP6_H__ + +#define DHCP6_SOLICIT 1 +#define DHCP6_ADVERTISE 2 +#define DHCP6_REQUEST 3 +#define DHCP6_CONFIRM 4 +#define DHCP6_RENEW 5 +#define DHCP6_REBIND 6 +#define DHCP6_REPLY 7 +#define DHCP6_RELEASE 8 +#define DHCP6_DECLINE 9 +#define DHCP6_RECONFIGURE 10 +#define DHCP6_INFORMATION_REQUEST 11 +#define DHCP6_RELAY_FORM 12 +#define DHCP6_RELAY_REPL 13 + +#define D6_OPT_CLIENTID 1 +#define D6_OPT_SERVERID 2 +#define D6_OPT_IA_NA 3 +#define D6_OPT_IA_TA 4 +#define D6_OPT_IAADDR 5 +#define D6_OPT_ORO 6 +#define D6_OPT_PREFERENCE 7 +#define D6_OPT_ELAPSED_TIME 8 +#define D6_OPT_RELAY_MSG 9 +#define D6_OPT_AUTH 11 +#define D6_OPT_UNICAST 12 +#define D6_OPT_STATUS_CODE 13 +#define D6_OPT_RAPID_COMMIT 14 +#define D6_OPT_USER_CLASS 15 +#define D6_OPT_VENDOR_CLASS 16 +#define D6_OPT_VENDOR_SPECIFIC 17 +#define D6_OPT_INTERFACE_ID 18 +#define D6_OPT_RECONF_MSG 19 +#define D6_OPT_RECONF_ACCEPT 20 +#define D6_OPT_DNS_SERVERS 23 +#define D6_OPT_DOMAIN_LIST 24 +#define D6_OPT_IA_PD 25 +#define D6_OPT_IAPREFIX 26 + +#define D6_STATUS_Success 0 +#define D6_STATUS_UnspecFail 1 +#define D6_STATUS_NoAddrsAvail 2 +#define D6_STATUS_NoBinding 3 +#define D6_STATUS_NotOnLink 4 +#define D6_STATUS_UseMulticast 5 +#define D6_STATUS_NoPrefixAvail 6 + +#define DUID_LLT 1 +#define DUID_EN 2 +#define DUID_LL 3 + + //~ 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F +//~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +//~ | D6_OPT_IA_PD | Longueur d’option | +//~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +//~ | IAID (4 octets) | +//~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +//~ | T1 (4 octets) | +//~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +//~ | T2 (4 octets) | +//~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +//~ | Options-IA_PD | +//~ . . +//~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +// Prefix for IA_PD + //~ 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F +//~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +//~ | OPTION_IAPREFIX | option-length | +//~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +//~ | preferred-lifetime | +//~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +//~ | valid-lifetime | +//~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +//~ | prefix-length | | +//~ +-+-+-+-+-+-+-+-+ IPv6 prefix | +//~ | (16 octets) | +//~ | | +//~ | | +//~ | | +//~ | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +//~ | | . +//~ +-+-+-+-+-+-+-+-+ . +//~ . IAprefix-options . +//~ . . +//~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + //~ 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F +//~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +//~ | D6_OPT_IA_NA | Longueur d’option | +//~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +//~ | IAID (4 octets) | +//~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +//~ | T1 (4 octets) | +//~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +//~ | T2 (4 octets) | +//~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +//~ | Options-IA_NA | +//~ . . +//~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + //~ 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F +//~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +//~ | OPTION_IA_TA | Longueur d’option | +//~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +//~ | IAID (4 octets) | +//~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +//~ | Options-IA_TA | +//~ . . +//~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +struct dhcp6_mess_hdr +{ + uint32_t type:8; + uint32_t trans_id:24; +} __attribute__((packed)); + +struct dhcp6_opt_h +{ + uint16_t code; + uint16_t len; +} __attribute__((packed)); + +struct dhcp6_duid +{ + uint16_t type; + union { + struct { + uint16_t htype; + uint32_t time; + uint8_t addr[0]; + } __attribute__((packed)) llt; + struct { + uint32_t enterprise; + uint8_t id[0]; + } __attribute__((packed)) en; + struct { + uint16_t htype; + uint8_t addr[0]; + } __attribute__((packed)) ll; + uint8_t raw[128]; + } u; +} __attribute__((packed)); + +struct dhcp6_opt_serverid +{ + struct dhcp6_opt_h opt_hdr; + struct dhcp6_duid duid; +} __attribute__((packed)); + +struct dhcp6_opt_clientid +{ + struct dhcp6_opt_h opt_hdr; + struct dhcp6_duid duid; +} __attribute__((packed)); + +struct dhcp6_opt_ia_na { + struct dhcp6_opt_h hdr; + uint32_t iaid; + uint32_t T1; + uint32_t T2; +} __attribute__((packed)); + +struct dhcp6_opt_ia_ta { + struct dhcp6_opt_h hdr; + uint32_t iaid; +} __attribute__((packed)); + +struct dhcp6_opt_ia_pd { + struct dhcp6_opt_h hdr; + uint32_t iaid; + uint32_t T1; + uint32_t T2; +} __attribute__((packed)); + +struct dhcp6_opt_ia_addr { + struct dhcp6_opt_h hdr; + struct in6_addr addr; + uint32_t pref_lifetime; + uint32_t valid_lifetime; +} __attribute__((packed)); + +struct dhcp6_opt_oro { + struct dhcp6_opt_h hdr; + uint16_t opt_demand[0]; +} __attribute__((packed)); + +struct dhcp6_opt_status { + struct dhcp6_opt_h hdr; + uint16_t code; +} __attribute__((packed)); + +struct dhcp6_opt_preference { + struct dhcp6_opt_h hdr; + uint8_t pref; +} __attribute__((packed)); + +struct dhcp6_opt_ia_prefix { + struct dhcp6_opt_h hdr; + uint32_t pref_lifetime; + uint32_t valid_lifetime; + uint8_t prefix_len; + struct in6_addr prefix; +} __attribute__((packed)); + +// dhcp6.c +void dhcpv6_process(uint16_t s, uint16_t t, uint8_t *p, uint16_t l); +void dhcpv6_init(void); + +#endif /* __DHCP6_H__ */ diff --git a/garden.c b/garden.c index 0795196..0e6880c 100644 --- a/garden.c +++ b/garden.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include "dhcp6.h" #include "l2tpns.h" #include "plugin.h" #include "control.h" diff --git a/icmp.c b/icmp.c index fa947b7..0d6c65e 100644 --- a/icmp.c +++ b/icmp.c @@ -1,32 +1,18 @@ // L2TPNS: icmp #include -#include -#include -#include #include #include #include -#include -#include #include -#include -#include -#include +#include +#include "dhcp6.h" #include "l2tpns.h" -#include "pppoe.h" +#include "ipv6_u.h" static uint16_t _checksum(uint8_t *addr, int count); -struct ipv6_pseudo_hdr { - struct in6_addr src; - struct in6_addr dest; - uint32_t ulp_length; - uint32_t zero : 24; - uint32_t nexthdr : 8; -}; - void host_unreachable(in_addr_t destination, uint16_t id, in_addr_t source, uint8_t *packet, int packet_len) { char buf[128] = {0}; @@ -85,11 +71,11 @@ static uint16_t _checksum(uint8_t *addr, int count) for (; count > 1; count -= 2) { - sum += ntohs(*(uint32_t *) addr); + sum += ntohs(*(uint16_t *) addr); addr += 2; } - if (count > 1) sum += *(unsigned char *)addr; + if (count > 0) sum += *(unsigned char *)addr; // take only 16 bits out of the 32 bit sum and add up the carries while (sum >> 16) @@ -104,75 +90,75 @@ static uint16_t _checksum(uint8_t *addr, int count) void send_ipv6_ra(sessionidt s, tunnelidt t, struct in6_addr *ip) { struct nd_opt_prefix_info *pinfo; - struct ipv6_pseudo_hdr *phdr; + struct ip6_hdr *p_ip6_hdr; + struct nd_router_advert *p_nra; uint8_t b[MAXETHER + 20]; - uint8_t c[MAXETHER + 20]; + struct ipv6_pseudo_hdr pseudo_hdr; int l; - uint8_t *o; LOG(3, s, t, "Sending IPv6 RA\n"); - + memset(b, 0, sizeof(b)); - o = makeppp(b, sizeof(b), 0, 0, s, t, PPPIPV6, 0, 0, 0); + p_ip6_hdr = (struct ip6_hdr *) makeppp(b, sizeof(b), 0, 0, s, t, PPPIPV6, 0, 0, 0); - if (!o) + if (!p_ip6_hdr) { LOG(3, s, t, "failed to send IPv6 RA\n"); return; } - *o = 0x60; // IPv6 - *(o+1) = 0; - *(o+5) = 48; // Length of payload (not header) - *(o+6) = 58; // icmp6 is next - *(o+7) = 255; // Hop limit - memset(o+8, 0, 16); // source = FE80::1 - *(o+8) = 0xFE; - *(o+9) = 0x80; - *(o+23) = 1; + p_ip6_hdr->ip6_vfc = 0x60; // IPv6 + p_ip6_hdr->ip6_plen = 0; // Length of payload (not header) (calculation below) + p_ip6_hdr->ip6_nxt = IPPROTO_ICMPV6; // icmp6 is next + p_ip6_hdr->ip6_hlim = 255; // Hop limit + // IPv6 0xFE80::1 + inet_pton(AF_INET6, "FE80::1", &p_ip6_hdr->ip6_src.s6_addr); + if (ip != NULL) { - memcpy(o+24, ip, 16); // dest = ip + memcpy(p_ip6_hdr->ip6_dst.s6_addr, ip, 16); // dest = ip } else { // FF02::1 - all hosts - *(o+24) = 0xFF; - *(o+25) = 2; - *(o+39) = 1; + inet_pton(AF_INET6, "FF02::1", &p_ip6_hdr->ip6_dst.s6_addr); } - *(o+40) = 134; // RA message - *(o+41) = 0; // Code - *(o+42) = *(o+43) = 0; // Checksum - *(o+44) = 64; // Hop count - *(o+45) = 0; // Flags - *(o+46) = *(o+47) = 255; // Lifetime - *(uint32_t *)(o+48) = 0; // Reachable time - *(uint32_t *)(o+52) = 0; // Retrans timer - pinfo = (struct nd_opt_prefix_info *)(o+56); + + // RA message after Ipv6 header + p_nra = (struct nd_router_advert *) &p_ip6_hdr[1]; + p_nra->nd_ra_type = ND_ROUTER_ADVERT; // RA message (134) + p_nra->nd_ra_code = 0; // Code + p_nra->nd_ra_cksum = 0; // Checksum + p_nra->nd_ra_curhoplimit = 64; // Hop count + p_nra->nd_ra_flags_reserved = (ND_RA_FLAG_MANAGED|ND_RA_FLAG_OTHER); // Flags + p_nra->nd_ra_router_lifetime = 0xFFFF; // Lifetime + p_nra->nd_ra_reachable = 0; // Reachable time + p_nra->nd_ra_retransmit = 0; // Retrans timer + // Option PI after RA message (rfc4861) + pinfo = (struct nd_opt_prefix_info *) &p_nra[1]; pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION; pinfo->nd_opt_pi_len = 4; - pinfo->nd_opt_pi_prefix_len = 64; // prefix length - pinfo->nd_opt_pi_flags_reserved = ND_OPT_PI_FLAG_ONLINK; - pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO; + pinfo->nd_opt_pi_flags_reserved = ND_OPT_PI_FLAG_ONLINK | ND_OPT_PI_FLAG_AUTO; pinfo->nd_opt_pi_valid_time = htonl(2592000); pinfo->nd_opt_pi_preferred_time = htonl(604800); pinfo->nd_opt_pi_reserved2 = 0; + pinfo->nd_opt_pi_prefix_len = 64; // prefix length pinfo->nd_opt_pi_prefix = config->ipv6_prefix; - l = sizeof(*pinfo) + 56; - memset(c, 0, sizeof(c)); - phdr = (struct ipv6_pseudo_hdr *) c; - memcpy(&phdr->src, o+8, 16); - memcpy(&phdr->dest, o+24, 16); - phdr->ulp_length = htonl(l - 40); - phdr->nexthdr = IPPROTO_ICMPV6; + // // Length of payload (not header) + p_ip6_hdr->ip6_plen = htons(sizeof(*pinfo) + sizeof(*p_nra)); - memcpy(c + sizeof(*phdr), o + 40, l - 40); + l = sizeof(*pinfo) + sizeof(*p_nra) + sizeof(*p_ip6_hdr); + /* Use pseudo hearder for checksum calculation */ + memset(&pseudo_hdr, 0, sizeof(pseudo_hdr)); + memcpy(&pseudo_hdr.src, &p_ip6_hdr->ip6_src, 16); + memcpy(&pseudo_hdr.dest, &p_ip6_hdr->ip6_dst, 16); + pseudo_hdr.ulp_length = htonl(sizeof(*pinfo) + sizeof(*p_nra)); // Lenght whitout Ipv6 header + pseudo_hdr.nexthdr = IPPROTO_ICMPV6; // Checksum is over the icmp6 payload plus the pseudo header - *(uint16_t *)(o+42) = _checksum(c, l - 40 + sizeof(*phdr)); + p_nra->nd_ra_cksum = ipv6_checksum(&pseudo_hdr, (uint8_t *) p_nra, (sizeof(*pinfo) + sizeof(*p_nra))); - tunnelsend(b, l + (o-b), t); // send it... + tunnelsend(b, l + (((uint8_t *) p_ip6_hdr)-b), t); // send it... return; } diff --git a/ipv6_u.c b/ipv6_u.c new file mode 100644 index 0000000..3c8ff12 --- /dev/null +++ b/ipv6_u.c @@ -0,0 +1,48 @@ +/* + * Fernando ALVES 2014 + * GPL licenced + */ + +#include + +#include "ipv6_u.h" + +uint16_t ipv6_checksum(struct ipv6_pseudo_hdr *p_pshdr, uint8_t *buff, int lenbuff) +{ + uint32_t sum = 0; + uint16_t *ptrw = (uint16_t *) p_pshdr; + uint16_t word16; + int i; + + // Size pseudo header 40 byte (20 word) + for (i = 0; i < (sizeof(*p_pshdr)/2); i++) + { + word16 = ntohs(*((uint16_t *)ptrw)); + sum += word16; + ++ptrw; + } + + ptrw = (uint16_t *) buff; + while (lenbuff > 1) + { + word16 = ntohs(*((uint16_t *) ptrw)); + sum += word16; + ++ptrw; + lenbuff -= 2; + } + + if (lenbuff > 0) + { + word16 = ntohs(*((uint8_t *) ptrw)); + sum += word16; + } + + // take only 16 bits out of the 32 bit sum and add up the carries + while (sum >> 16) + sum = (sum & 0xFFFF) + (sum >> 16); + + // one's complement the result + sum = ~sum; + + return htons((uint16_t) sum); +} diff --git a/ipv6_u.h b/ipv6_u.h new file mode 100644 index 0000000..6c1c7b5 --- /dev/null +++ b/ipv6_u.h @@ -0,0 +1,16 @@ + +#ifndef __IPV6_U_H__ +#define __IPV6_U_H__ + +struct ipv6_pseudo_hdr { + struct in6_addr src; + struct in6_addr dest; + uint32_t ulp_length; + uint32_t zero : 24; + uint32_t nexthdr : 8; +} __attribute__((packed)); + +// dhcp6.c +uint16_t ipv6_checksum(struct ipv6_pseudo_hdr *p_pshdr, uint8_t *buff, int lenbuff); + +#endif /* __IPV6_U_H__ */ diff --git a/l2tplac.c b/l2tplac.c index 0d11b45..4140258 100644 --- a/l2tplac.c +++ b/l2tplac.c @@ -7,8 +7,10 @@ #include #include +#include #include "md5.h" +#include "dhcp6.h" #include "l2tpns.h" #include "util.h" #include "cluster.h" diff --git a/l2tpns.c b/l2tpns.c index 04fe44b..07a45f7 100644 --- a/l2tpns.c +++ b/l2tpns.c @@ -40,6 +40,7 @@ #include #include "md5.h" +#include "dhcp6.h" #include "l2tpns.h" #include "cluster.h" #include "plugin.h" @@ -55,6 +56,7 @@ #include "l2tplac.h" #include "pppoe.h" +#include "dhcp6.h" char * Vendor_name = "Linux L2TPNS"; uint32_t call_serial_number = 0; @@ -189,6 +191,12 @@ config_descriptt config_values[] = { CONFIG("pppoe_only_equal_svc_name", pppoe_only_equal_svc_name, BOOL), CONFIG("multi_hostname", multi_hostname, STRING), CONFIG("no_throttle_local_IP", no_throttle_local_IP, BOOL), + CONFIG("dhcp6_preferred_lifetime", dhcp6_preferred_lifetime, INT), + CONFIG("dhcp6_valid_lifetime", dhcp6_valid_lifetime, INT), + CONFIG("dhcp6_server_duid", dhcp6_server_duid, INT), + CONFIG("primary_ipv6_dns", default_ipv6_dns1, IPv6), + CONFIG("secondary_ipv6_dns", default_ipv6_dns2, IPv6), + CONFIG("default_ipv6_domain_list", default_ipv6_domain_list, STRING), { NULL, 0, 0, 0 } }; @@ -2123,6 +2131,11 @@ void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_e if (session[s].ipv6route.s6_addr[0] && session[s].ipv6prefixlen && del_routes) route6set(s, session[s].ipv6route, session[s].ipv6prefixlen, 0); + if (session[s].ipv6address.s6_addr[0] && del_routes) + { + route6set(s, session[s].ipv6address, 128, 0); + } + if (b) { // This session was part of a bundle @@ -2178,6 +2191,11 @@ void sessionshutdown(sessionidt s, char const *reason, int cdn_result, int cdn_e // IPV6 route if (session[new_s].ipv6prefixlen) cache_ipv6map(session[new_s].ipv6route, session[new_s].ipv6prefixlen, new_s); + + if (session[new_s].ipv6address.s6_addr[0]) + { + cache_ipv6map(session[new_s].ipv6address, 128, new_s); + } } } } @@ -3415,6 +3433,20 @@ void processudp(uint8_t *buf, int len, struct sockaddr_in *addr, uint16_t indexu return; } + if (!config->cluster_iam_master) + { + // Check if DhcpV6, IP dst: FF02::1:2, Src Port 0x0222 (546), Dst Port 0x0223 (547) + if (*(p + 6) == 17 && *(p + 24) == 0xFF && *(p + 25) == 2 && + *(uint32_t *)(p + 26) == 0 && *(uint32_t *)(p + 30) == 0 && + *(uint16_t *)(p + 34) == 0 && *(p + 36) == 0 && *(p + 37) == 1 && *(p + 38) == 0 && *(p + 39) == 2 && + *(p + 40) == 2 && *(p + 41) == 0x22 && *(p + 42) == 2 && *(p + 43) == 0x23) + { + // DHCPV6 must be managed by the Master. + master_forward_packet(buf, len, addr->sin_addr.s_addr, addr->sin_port, indexudpfd); + return; + } + } + processipv6in(s, t, p, l); } else if (session[s].ppp.lcp == Opened) @@ -5102,6 +5134,7 @@ int main(int argc, char *argv[]) init_tbf(config->num_tbfs); LOG(0, 0, 0, "L2TPNS version " VERSION "\n"); + LOG(0, 0, 0, "Copyright (c) 2012, 2013, 2014 ISP FDN & SAMESWIRELESS\n"); LOG(0, 0, 0, "Copyright (c) 2003, 2004, 2005, 2006 Optus Internet Engineering\n"); LOG(0, 0, 0, "Copyright (c) 2002 FireBrick (Andrews & Arnold Ltd / Watchfront Ltd) - GPL licenced\n"); { @@ -5177,6 +5210,7 @@ int main(int argc, char *argv[]) initrad(); initippool(); + dhcpv6_init(); // seed prng { @@ -5823,6 +5857,11 @@ int load_session(sessionidt s, sessiont *new) if (session[s].ipv6route.s6_addr[0] && session[s].ipv6prefixlen) route6set(s, session[s].ipv6route, session[s].ipv6prefixlen, 0); + if (session[s].ipv6address.s6_addr[0]) + { + route6set(s, session[s].ipv6address, 128, 0); + } + routed = 0; // add new routes... @@ -5850,7 +5889,12 @@ int load_session(sessionidt s, sessiont *new) // check v6 routing if (new->ipv6prefixlen && new->ppp.ipv6cp == Opened && session[s].ppp.ipv6cp != Opened) - route6set(s, new->ipv6route, new->ipv6prefixlen, 1); + route6set(s, new->ipv6route, new->ipv6prefixlen, 1); + + if (new->ipv6address.s6_addr[0] && new->ppp.ipv6cp == Opened && session[s].ppp.ipv6cp != Opened) + { + route6set(s, new->ipv6address, 128, 1); + } // check filters if (new->filter_in && (new->filter_in > MAXFILTER || !ip_filters[new->filter_in - 1].name[0])) diff --git a/l2tpns.h b/l2tpns.h index 73b5455..d92c274 100644 --- a/l2tpns.h +++ b/l2tpns.h @@ -15,7 +15,7 @@ #include #include -#define VERSION "2.2.1" +#define VERSION "2.2.1-2fdn3.13" // Limits #define MAXTUNNEL 500 // could be up to 65535 @@ -333,6 +333,10 @@ typedef struct struct in6_addr ipv6route; // Static IPv6 route sessionidt forwardtosession; // LNS id_session to forward uint8_t src_hwaddr[ETH_ALEN]; // MAC addr source (for pppoe sessions 6 bytes) + uint32_t dhcpv6_prefix_iaid; // prefix iaid requested by client + uint32_t dhcpv6_iana_iaid; // iaid of iana requested by client + struct in6_addr ipv6address; // Framed Ipv6 address + struct dhcp6_opt_clientid dhcpv6_client_id; // Size max (headers + DUID) char reserved[4]; // Space to expand structure without changing HB_VERSION } sessiont; @@ -620,6 +624,7 @@ struct Tstats uint32_t call_radiussend; uint32_t call_radiusretry; uint32_t call_random_data; + uint32_t call_dhcpv6_process; #endif }; @@ -789,6 +794,12 @@ typedef struct char bind_multi_address[256]; char multi_hostname[512]; char multi_n_hostname[MAX_NBHOSTNAME][MAXHOSTNAME]; // list hostname + struct in6_addr default_ipv6_dns1; + struct in6_addr default_ipv6_dns2; + uint32_t dhcp6_preferred_lifetime; // preferred lifetime (see rfc3315) + uint32_t dhcp6_valid_lifetime; // valid lifetime (see rfc3315) + uint32_t dhcp6_server_duid; // DUID of dhcpv6 server (see rfc3315) + char default_ipv6_domain_list[255]; } configt; enum config_typet { INT, STRING, UNSIGNED_LONG, SHORT, BOOL, IPv4, IPv6 }; diff --git a/nsctl.c b/nsctl.c index 59ad0c6..4e19468 100644 --- a/nsctl.c +++ b/nsctl.c @@ -8,6 +8,7 @@ #include #include +#include "dhcp6.h" #include "l2tpns.h" #include "control.h" diff --git a/ppp.c b/ppp.c index e786c16..3a045ce 100644 --- a/ppp.c +++ b/ppp.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include "dhcp6.h" #include "l2tpns.h" #include "constants.h" #include "plugin.h" @@ -1483,6 +1485,13 @@ static void ipv6cp_open(sessionidt s, tunnelidt t) if (session[s].ipv6prefixlen) route6set(s, session[s].ipv6route, session[s].ipv6prefixlen, 1); + if (session[s].ipv6address.s6_addr[0]) + { + // Check if included in prefix + if (sessionbyipv6(session[s].ipv6address) != s) + route6set(s, session[s].ipv6address, 128, 1); + } + // Send an initial RA (TODO: Should we send these regularly?) send_ipv6_ra(s, t, NULL); } @@ -2260,6 +2269,16 @@ void processipv6in(sessionidt s, tunnelidt t, uint8_t *p, uint16_t l) return; } + // Check if DhcpV6, IP dst: FF02::1:2, Src Port 0x0222 (546), Dst Port 0x0223 (547) + if (*(p + 6) == 17 && *(p + 24) == 0xFF && *(p + 25) == 2 && + *(uint32_t *)(p + 26) == 0 && *(uint32_t *)(p + 30) == 0 && + *(uint16_t *)(p + 34) == 0 && *(p + 36) == 0 && *(p + 37) == 1 && *(p + 38) == 0 && *(p + 39) == 2 && + *(p + 40) == 2 && *(p + 41) == 0x22 && *(p + 42) == 2 && *(p + 43) == 0x23) + { + dhcpv6_process(s, t, p, l); + return; + } + // Add on the tun header p -= 4; *(uint32_t *) p = htonl(PKTIPV6); diff --git a/pppoe.c b/pppoe.c index 4d442cc..c6bc12d 100644 --- a/pppoe.c +++ b/pppoe.c @@ -22,6 +22,7 @@ #include #include +#include "dhcp6.h" #include "l2tpns.h" #include "cluster.h" #include "constants.h" diff --git a/radius.c b/radius.c index 4321d82..76ff390 100644 --- a/radius.c +++ b/radius.c @@ -14,6 +14,7 @@ #include "md5.h" #include "constants.h" +#include "dhcp6.h" #include "l2tpns.h" #include "plugin.h" #include "util.h" @@ -773,7 +774,7 @@ void processrad(uint8_t *buf, int len, char socket_index) int prefixlen; uint8_t *n = p + 2; uint8_t *e = p + p[1]; - uint8_t *m = memchr(n, '/', e - p); + uint8_t *m = memchr(n, '/', e - n); *m++ = 0; inet_pton(AF_INET6, (char *) n, &r6); @@ -792,6 +793,28 @@ void processrad(uint8_t *buf, int len, char socket_index) session[s].ipv6prefixlen = prefixlen; } } + else if (*p == 123) + { + // Delegated-IPv6-Prefix + if ((p[1] > 4) && (p[3] > 0) && (p[3] <= 128)) + { + char ipv6addr[INET6_ADDRSTRLEN]; + memcpy(&session[s].ipv6route, &p[4], p[1] - 4); + session[s].ipv6prefixlen = p[3]; + LOG(3, s, session[s].tunnel, " Radius reply contains Delegated IPv6 Prefix %s/%d\n", + inet_ntop(AF_INET6, &session[s].ipv6route, ipv6addr, INET6_ADDRSTRLEN), session[s].ipv6prefixlen); + } + } + else if (*p == 168) + { + // Framed-IPv6-Address + if (p[1] == 18) + { + char ipv6addr[INET6_ADDRSTRLEN]; + memcpy(&session[s].ipv6address, &p[2], 16); + LOG(3, s, session[s].tunnel, " Radius reply contains Framed-IPv6-Address %s\n", inet_ntop(AF_INET6, &session[s].ipv6address, ipv6addr, INET6_ADDRSTRLEN)); + } + } else if (*p == 25) { // Class diff --git a/sessionctl.c b/sessionctl.c index 805b794..97e6111 100644 --- a/sessionctl.c +++ b/sessionctl.c @@ -1,4 +1,6 @@ #include +#include +#include "dhcp6.h" #include "l2tpns.h" #include "plugin.h" #include "control.h" diff --git a/setrxspeed.c b/setrxspeed.c index 52fcf4a..a808c85 100644 --- a/setrxspeed.c +++ b/setrxspeed.c @@ -1,4 +1,6 @@ #include +#include +#include "dhcp6.h" #include "l2tpns.h" #include "plugin.h" diff --git a/snoopctl.c b/snoopctl.c index d538a23..ab850f0 100644 --- a/snoopctl.c +++ b/snoopctl.c @@ -1,4 +1,6 @@ #include +#include +#include "dhcp6.h" #include "l2tpns.h" #include "plugin.h" #include "control.h" diff --git a/stripdomain.c b/stripdomain.c index 877617e..d14e5d3 100644 --- a/stripdomain.c +++ b/stripdomain.c @@ -1,4 +1,6 @@ #include +#include +#include "dhcp6.h" #include "l2tpns.h" #include "plugin.h" diff --git a/tbf.c b/tbf.c index 93e1025..4835ecc 100644 --- a/tbf.c +++ b/tbf.c @@ -1,6 +1,8 @@ // L2TPNS: token bucket filters #include +#include +#include "dhcp6.h" #include "l2tpns.h" #include "util.h" #include "tbf.h" diff --git a/throttlectl.c b/throttlectl.c index adcff27..ef194f4 100644 --- a/throttlectl.c +++ b/throttlectl.c @@ -1,4 +1,6 @@ #include +#include +#include "dhcp6.h" #include "l2tpns.h" #include "plugin.h" #include "control.h" diff --git a/util.c b/util.c index bbf94ba..ff6bf1e 100644 --- a/util.c +++ b/util.c @@ -9,6 +9,7 @@ #include #include +#include "dhcp6.h" #include "l2tpns.h" #ifdef BGP #include "bgp.h"