Import Upstream version 1.10.0

This commit is contained in:
openKylinBot 2022-05-14 02:44:05 +08:00
commit 04aa3f451d
49 changed files with 7883 additions and 0 deletions

34
AUTHORS Normal file
View File

@ -0,0 +1,34 @@
Primary author of this package (when it was called pptp-linux):
C. Scott Ananian <cananian@alumni.princeton.edu>
Patches and bug-fixes by:
Christoph Lameter <christoph@lameter.com>
Gordon Chaffee <chaffee@HOME.COM>
mulix <mulix@actcom.co.il>
James Cameron <quozl@laptop.org>
Rein Klazes <rklazes@xs4all.nl>
Thomas Quinot <thomas@cuivre.fr.eu.org>
Rhialto <rhialto@azenomei.knuffel.net>
Scott Venier <scott@scooter.cx>
Jeff Wiedemeier <Jeff.Wiedemeier@hp.com>
Yura Zotov <yz@altlinux.ru>
Chris Wilson <chris@netservers.co.uk>
Ed Marcotte <epm@cisco.com>
Jan Pieter <jp@jp.dhs.org>
Ed Meaney <epm@cisco.com>
Yury Tarasievich <grog@grsu.by>
Paul Howarth <paul@city-fan.org>
Peter Surda <shurdeek@routehat.org>
Nelson Ferraz <nferraz@gmail.com>
Michael Adda <michael@hackers.co.il>
Ilya Voronin <ivoronin@gmail.com>
Charles Shen <cshen@cisco.com>
Jan Just Keijser <jan.just.keijser@gmail.com>
David Lamparter <equinox@diac24.net>
Ruslan Atnabayeff <rfatnabayeff at gmail.com>
Package renamed from pptp-linux to pptp after version 1.5.0.
$Id: AUTHORS,v 1.21 2011/02/22 02:25:24 quozl Exp $

339
COPYING Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

984
ChangeLog Normal file
View File

@ -0,0 +1,984 @@
Thu Jan 18 11:10:32 2018 James Cameron <quozl@laptop.org>
* pptp-1.10.0: released.
[this file is not maintained, see NEWS and "git log"]
Tue Nov 29 16:13:57 2016 James Cameron <quozl@laptop.org>
* pptp-1.9.0: released.
[this file is not maintained, see "git log"]
Wed Oct 23 19:04:57 2013 James Cameron <quozl@laptop.org>
* pptp-1.8.0: released.
Thu Aug 30 13:45:26 2012 Paul Howarth <paul@city-fan.org>
* options.pptp: fix typo in 'Encryption' comment, add notes and
references regarding recent chapcrack exploit, note that the
ppp_mppe kernel module will not load into the kernel if it's
booted in FIPS mode (http://bugzilla.redhat.com/845112), and fix
broken link to Jan Dubiec's ppp_mppe_mppc code.
Wed Nov 30 09:02:18 2011 Paul Howarth <paul@city-fan.org>
* Makefile (config.h): fix unexpected build failure with a
highly-parallel build (-j16).
Thu Mar 3 12:24:15 2011 David Lamparter <david.lamparter@adyton.net>
* pptp.c, pptp_callmgr.c, pptp.8: add -nohostroute option to
disable adding a host route for the pptp server to the routing
table. Also add some documentation while at it.
Mon Feb 21 15:01:14 2011 David Lamparter <david.lamparter@adyton.net>
* pptp.c, pptp_callmgr.c, pptp_gre.c, pptp.8: add --rtmark option
for specifying the Linux policy routing / netfilter mark.
Thu Sep 30 16:16:58 2010 Paul Howarth <paul@city-fan.org>
* pptp_ctrl.c: we could maintain a separate vector of peer call
IDs and use that when we get a call-disconnect-notify packet to
find our call ID and close that call, but as
call-disconnect-notify packets are relatively rare, I've tried a
slower but simpler approach of doing a linear search through the
existing vector to look for the peer's call ID.
Tue Jun 15 15:02:28 2010 James Cameron <quozl@us.netrek.org>
* pptp.c (open_callmgr): fix usage of status returned by waitpid;
it must be wrapped by WEXITSTATUS to shift bits as required.
Tue Jun 15 15:00:40 2010 James Cameron <quozl@laptop.org>
* pptp_ctrl.c (pptp_conn_is_dead): immediately destroying the
connection and freeing the structure has led to segmentation
faults on more recent heap implementations, since we use the
structure after it has been freed.
Defer the free of the structure until after all uses of it have
ceased, by adding a connection state for dead and terminating the
main loop once it is detected.
Fri Jun 4 10:54:04 2010 Jan Just Keijser <jan.just.keijser@gmail.com>
* pptp_ctrl.c: check for failure return by pptp_send_ctrl_packet
and avoid using freed struct conn.
Tue Nov 10 15:39:33 2009 Charles Shen <cshen@cisco.com>
* pptp_ctrl.c (ctrlp_disp): add call ID of outgoing call so that
Call-Disconnect-Notify from peer causes correct disconnection
sequence.
Thu Jun 25 11:39:24 2009 James Cameron <quozl@us.netrek.org>
* AUTHORS: maintainer mail address change, james.cameron@hp.com is
no longer valid.
Mon Jun 1 14:43:00 2009 Paul Howarth <paul@city-fan.org>
* pptpsetup: only check for MPPE support in kernel and pppd if
an encrypted tunnel is being created.
Wed Mar 25 13:38:00 2009 Paul Howarth <paul@city-fan.org>
* pptpsetup: retain permissions on chap-secrets file when
deleting tunnels (http://bugzilla.redhat.com/492090).
Thu Jul 24 15:51:30 2008 Paul Howarth <paul@city-fan.org>
* routing.c, pptp_compat.c: compilation fixes for old
distributions.
Thu Jul 24 15:28:32 2008 Ilya Voronin <ivoronin@gmail.com>
* routing.c, Makefile: fixe use of /bin/ip and all compiler
warnings on Solaris.
Thu May 22 09:44:19 2008 James Cameron <quozl@us.netrek.org>
* routing.c: add config.h and use IP_BINARY.
* Makefile (IP): add pointer to IP binary, store it in config.h,
and add dependencies to support parallel make and development.
Wed May 14 15:59:17 2008 James Cameron <quozl@us.netrek.org>
* pptp-1.7.2 released.
Fri Jan 11 13:20:18 2008 Ilya Voronin <ivoronin@gmail.com>
* ppp_fcs.h, pptp.c, pptp_ctrl.h, pptp_gre.h, pptp_msg.h: port to
Solaris 10/11.
Wed Nov 21 14:29:46 2007 Leo Savernik <l.savernik@aon.at>
* pptp_ctrl.c (pptp_fd_set): fix compile with an ANSI
C89-compliant compiler.
Tue Aug 28 10:17:36 2007 James Cameron <quozl@us.netrek.org>
* README, pptp.c: assign copyright to Free Software Foundation,
and make license explicit.
Signed-off-by: "C. Scott Ananian" <cscott@cscott.net>
Wed Apr 4 16:30:24 2007 James Cameron <quozl@us.netrek.org>
* pptp.8, pptp.c: add --test-type and --test-rate options.
* pptp_gre.c: use alternate write(2) function for sending GRE
packets.
* test.c: implement reordering tests to assist with pptpd testing.
These tests reorder the stream to simulate real-world examples.
Fri Dec 15 02:02:08 2006 Michael Adda <michael@hackers.co.il>
* pptp_gre.c: when we fail to write due to a transient error
simply ignore it (treat it as a drop).
Thu Oct 12 13:52:46 2006 James Cameron <quozl@us.netrek.org>
* pptp_gre.c (pptp_gre_copy): select(2) may return error, and the
code was checking the read file descriptors without checking if
they are valid.
Thu Aug 17 14:36:18 2006 James Cameron <quozl@us.netrek.org>
* Makefile: add pptpsetup man page using pod2man.
Wed Aug 2 16:21:08 2006 James Cameron <quozl@us.netrek.org>
* routing.c, routing.h, pptp_callmgr.c (callmgr_main): add route
to PPTP server. Experimental feature. Note that this has a
side-effect of leaving a route to the server in place after the
tunnel has terminated.
Wed Aug 2 16:19:06 2006 James Cameron <quozl@us.netrek.org>
* pptp.c: fix a few compilation warnings.
Wed Aug 2 16:02:23 2006 James Cameron <quozl@us.netrek.org>
* pptpsetup: merge updates from Nelson Ferraz as of 24th April.
* Makefile (dist): include pptpsetup in kit.
Thu Apr 20 08:52:45 2006 James Cameron <quozl@us.netrek.org>
* Makefile (dist): remove Reference documentation as the license
is non-free. The documentation is available from other sources.
Thu Apr 20 08:49:01 2006 James Cameron <quozl@us.netrek.org>
* pptp.8: merge Debian contribution in 1.7.0-2 by Ola Lundqvist.
Mon Apr 3 15:28:37 2006 James Cameron <quozl@us.netrek.org>
* pptpsetup: add script contributed by Nelson Ferraz.
Mon Mar 27 10:09:20 2006 James Cameron <quozl@us.netrek.org>
* options.pptp: add refuse-pap to default options, along with a
comment that a server may need to use PAP or CHAP if it is not
using MPPE.
Mon Feb 13 14:01:34 2006 James Cameron <quozl@us.netrek.org>
* pptp-1.7.1 released.
Fri Feb 10 10:59:31 2006 James Cameron <quozl@us.netrek.org>
* pptp.c: use prctl(2) to set process name for gateway process so
that killall(1) of pptp will affect control connection call
manager only.
Mon Aug 29 15:42:03 2005 James Cameron <quozl@us.netrek.org>
* pptp.c: add --version feature.
Mon Aug 22 10:46:38 2005 James Cameron <quozl@us.netrek.org>
* util.c (sigpipe_assign): remove superfluous sigset variable
and calls; they served no purpose. Reported by: Pavol Gono.
Sat Aug 20 23:14:25 2005 James Cameron <quozl@us.netrek.org>
* options.pptp: default to not require MPPE, per Red Hat Bugzilla
#166394.
Thu Aug 11 10:46:32 2005 James Cameron <quozl@us.netrek.org>
* PROTOCOL-SECURITY: add write-up regarding protocol security risks.
* Makefile (dist): add PROTOCOL-SECURITY write-up.
Wed Jul 27 20:49:30 2005 James Cameron <quozl@us.netrek.org>
* pptp-1.7.0 released.
Mon Jul 11 13:17:37 2005 James Cameron <quozl@us.netrek.org>
* pptp_gre.c (decaps_gre): silently discard packets that are not
for this call. Reported by: Alan Jenkins.
Thu Mar 31 17:41:17 2005 James Cameron <quozl@us.netrek.org>
* pptp_ctrl.c (pptp_dispatch): handle signals first, since there's
a possibility of premature return from the function.
* pptp_callmgr.c (callmgr_main): terminate faster when peer closes
control connection.
Thu Mar 10 11:07:52 2005 James Cameron <quozl@us.netrek.org>
* pptp_ctrl.c (pptp_handle_timer): when we close connection due to
loss of echo replies, say so in the log.
Reported by: Jean Wolter.
* pptp_ctrl.c: fix signal deadlock on kernel 2.6.x
Reported by: Jean Wolter.
* util.c, util.h: adopt sigpipe implementation from pptpd.
* pptp_ctrl.c (pptp_conn_open): use sigpipe implementation instead
of trying I/O in signal handler (which causes deadlocks).
* pptp_ctrl.c (pptp_fd_set): include the sigpipe in the file
descriptor set.
* pptp_ctrl.c (pptp_dispatch): detect queued signals via sigpipe.
* pptp_ctrl.c (pptp_conn_destroy): close the sigpipe.
Fri Feb 18 12:38:18 2005 James Cameron <quozl@us.netrek.org>
* pptp-1.6.0 released.
Fri Feb 18 12:38:02 2005 James Cameron <quozl@us.netrek.org>
* Makefile (install): move options.pptp to this package from the
RPM spec file.
Tue Dec 14 08:56:07 2004 James Cameron <quozl@us.netrek.org>
* pptp_ctrl.c (ctrlp_disp): fix typo. From: Avi Kivity
<avi@argo.co.il>
Tue Dec 7 09:43:00 2004 James Cameron <quozl@us.netrek.org>
* pptp_ctrl.c: add error propagation to the ctrlp_disp callchain,
so that we don't double-free the connection on a stop control
connection reply. From: Avi Kivity <avi@argo.co.il>
Wed Nov 10 09:49:48 2004 James Cameron <quozl@us.netrek.org>
* util.{c,h}: recent compilers spew a packetload of compilation
warnings. From: Avi Kivity <avi@argo.co.il>
Tue Nov 9 12:30:57 2004 James Cameron <quozl@us.netrek.org>
* pptp.{8,c}, pptp_ctrl.c, pptp_options.h: add --idle-wait (time
to wait before sending an echo request on the control connection)
and --max-echo-wait (time to wait before giving up on lack of
reply to an echo request). The latter is not yet implemented.
Tue Nov 9 12:23:48 2004 James Cameron <quozl@us.netrek.org>
* pptp_callmgr.c, pptp_ctrl.{c,h}: pptp_dispatch and its
subordinates insist on handling fatal errors by calling
pptp_conn_destroy. unfortunately, as the comments say,
callmgr_main uses the connection afterwards with the usual
results. Added error propagation to the routines mentioned,
allowing callmgr_main to have the honor of closing the connection.
From: Avi Kivity <avi@argo.co.il>
Wed Oct 27 21:03:28 2004 James Cameron <quozl@us.netrek.org>
* pptp_callmgr.c (callmgr_main): pptp sometimes crashes in
pptp_fd_set and leaves a core dump. Think this is due to a signal
being caught and longjmp'ed to callmgr_main's shutdown label after
we are out of that function, causing garbage local variables to be
used. From: Avi Kivity <avi@argo.co.il>
Wed Jul 21 16:52:01 CEST 2004 Rein Klazes <rklazes@xs4all.nl>
* pptp_ctrl.c (ctrlp_rep): Do not log sending of echo requests,
preventing dead-locks observed with Linux 2.6 systems.
The syslog call is not reentrant and must not be used within a
signal handler. A better solution would probably be to get rid of
the SIGALRM timer altogether.
Wed Jul 21 19:00:59 2004 Peter Surda <shurdeek@routehat.org>
* pptp_callmgr.c (callmgr_main): prevent kill of init.
Sat Jun 26 14:37:10 2004 James Cameron <quozl@us.netrek.org>
* pptp_gre.c (decaps_hdlc): portability fix, use IPPROTO_IP in
place of SOL_IP in getsockopt(). From: Thomas Quinot
<thomas@cuivre.fr.eu.org>
Tue Jun 22 19:08:58 2004 James Cameron <quozl@us.netrek.org>
* Makefile, AUTHORS, rename package from pptp-linux to pptp.
Tue Jun 22 18:08:27 2004 James Cameron <quozl@us.netrek.org>
* pptp-linux-1.5.0 released.
Fri Jun 11 09:28:05 2004 Chris Wilson <chris@netservers.co.uk>
* pptp.8, pptp_gre.c: make the statistics work properly when
buffering is disabled. Fix the issue with log messages claiming
buffering when no buffering is being done.
Thu Jun 10 16:58:53 2004 James Cameron <quozl@us.netrek.org>
* pptp.c (main): remove the sleep(3) on termination; it isn't
really required; and causes the GRE-to-PPP gateway process to hang
around after the connection has been terminated.
* pptp.c (open_callmgr): call manager was inheriting the GRE
socket, so close it before launching the callmgr, a regression
introduced 18th July 2002, in the patch to bind the GRE socket
earlier.
Thu Jun 10 08:34:17 CEST 2004 Rein Klazes <rklazes@xs4all.nl>
* pptp_callmgr.c: fix a case when the call manager does not
shutdown properly, a regression introduced by the changes on
2003 Oct 22 and 23.
Wed Jun 9 10:08:02 2004 Chris Wilson <chris@netservers.co.uk>
* pptp.8, pptp.c, pptp_gre.c, pptp_gre.h: add --nobuffer option to
eliminate all buffering of packets, a "pptp quake patch".
Wed Jun 9 09:37:06 2004 Paul Howarth <paul@city-fan.org>
* inststr.c: fix non-setting of the command line.
Tue Jun 8 21:25:27 2004 James Cameron <quozl@us.netrek.org>
* pptp-linux-1.5.0-rc1 released.
Sat Jun 5 22:44:50 2004 James Cameron <quozl@us.netrek.org>
* pptp_ctrl.c (pptp_read_some): fix for CPU loop after pppd killed
with -9, if read() returns zero, it is because the control
connection has closed, so destroy the connection.
Wed Mar 24 08:45:12 2004 Mark-Andre Hopf <mhopf@innominate.com>
* pptp.c: fix compile for ARM architecture.
Mon Mar 8 11:04:00 2004 Chris Wilson <chris@netservers.co.uk>
* pptp.8: added documentation for command-line options where
missing. Updated to reflect the use of getopt.
Tue Mar 2 09:53:53 2004 Peter McCurdy <pmccurdy@nit.ca>
* pptp.c (main, do_nothing): do not hang when a connection is
refused. When the controlling process (pptp.c) paused while
waiting for the child to send SIGUSR1, if the child died then the
controlling process wouldn't ever wake up. Now if the child dies,
SIGCHLD gets handled and the controlling process quits.
Tue Feb 10 20:35:18 2004 James Cameron <quozl@us.netrek.org>
* pptp_gre.c (decaps_hdlc): temporarily add code that captures
additional detail if EMSGSIZE is returned by read().
Fri Jan 2 10:05:17 2004 James Cameron <quozl@us.netrek.org>
* pptp-linux-1.4.0 released.
Mon Dec 1 11:58:24 2003 James Cameron <quozl@us.netrek.org>
* pptp.c (main): remove arguments debugging printf.
Wed Nov 26 12:22:00 2003 Chris Wilson <chris@netservers.co.uk>
* pptp.c: fixed argument handling so that hostname can be supplied
anywhere on the command line, not just at the start. pppd options
starting with "-" but before "--" are no longer supported.
* pptp.c: added some spacing to improve readability, removed
pointless "Step X" comments.
* pptp.c: fixed usage message: there should not be a "pppd" in the
command line.
Mon Nov 10 15:39:41 2003 James Cameron <quozl@us.netrek.org>
* pptp-linux-1.4.0-rc1 released.
Thu Oct 23 12:48:54 2003 James Cameron <quozl@us.netrek.org>
* pptp_callmgr.c (callmgr_main): if connection fails, pptp enters
a CPU loop calling select() with no file descriptors set, and
being given EBADF. Introduced by yesterday's modifications.
Correct code to detect this situation and break the main loop.
Wed Oct 22 13:02:04 2003 James Cameron <quozl@us.netrek.org>
* pptp_ctrl.c (pptp_call_open): add an assertion to prevent a call
open attempt while the control connection is not established.
* pptp_callmgr.c (callmgr_main): avoid accepting a UNIX socket
connection and therefore calling pptp_call_open() if the control
connection has not yet been established.
* pptp_ctrl.c (pptp_conn_established): add function for
pptp_callmgr.c to use to determine if the control connection has
been established.
TODO: if a connection reply is not received, what happens?
Reported by: John BouAntoun
Mon Sep 8 10:33:41 2003 James Cameron <quozl@us.netrek.org>
* pptp.c: fix for compile on OpenBSD. From: Waldemar Brodkorb
Mon Aug 18 12:12:00 2003 Chris Wilson <chris@netservers.co.uk>
* pptp.c pptp_gre.c util.h: add log level control, to increase
or reduce verbosity of log messages, for debugging and for people
who have lossy connections.
Thu Aug 7 12:20:09 2003 James Cameron <quozl@us.netrek.org>
* pptp_gre.c (decaps_gre): fix reporting of packet loss.
From: Chris Wilson
Wed Jun 25 12:59:28 2003 Rein Klazes <rklazes@xs4all.nl>
* pptp_callmgr.c: Wait for the replies on our Call-Clear-Request's and
Stop-Control-Connection-Request's.
* pptp_ctrl.c: small tweak in a message about non existant call:
report the received call ID's.
Sun Jun 22 19:08:14 2003 Rein Klazes <rklazes@xs4all.nl>
* pptp_ctrl.c: Log the buffering and sending of ALL control
messages (except Echo messages and Replies of course).
Change the way the sending of these messages is done. The
original way was to first put them into a buffer ( in
pptp_send_ctrl_packet()) and at some later write the buffered
bytes to the socket ( in pptp_write_some()). Now
pptp_send_ctrl_packet first attempts to write the packet directly.
Only it the write() does not write all of the bytes, the remaining
ones are buffered. This should help to track bugs in this area (like
one sending two Start-Control-Request's).
Thu Jun 19 09:09:53 2003 Rein Klazes <rklazes@xs4all.nl>
* pptp_ctrl.c: Improve logging of received control packets:
Move duplicated code to report on Result codes and General errors
to a separate function; Verbosely report error codes embedded in
start-control-connection replies; Translated some French comment;
Log when an unexpected Outgoing Call Reply is received; Log the
receipt of ALL control messages (except in case of echo
request/reply packets of which only the first 10 are logged);
Shorten the name of the function "pptp_dispatch_ctrl_packet" to
"ctrlp_disp", 25 characters is just too much in the log files.
Thu Jun 19 10:11:26 2003 Jan Pieter <jp@jp.dhs.org>
* Makefile (uninstall): include uninstall target, and a minor fix
to dist.
Wed Jun 18 12:19:09 2003 Rein Klazes <rklazes@xs4all.nl>
* pptp_gre.c: Instead of logging the (a)synchronous mode
of ppp, only issue a warning when it conflicts with the
mode of pptp.
Comparing two sequence numbers for(in)equality is safe even when
a wrap-around has occurred. This contrasts with comparing for
smaller/bigger. Remove a few unneeded tests for wrap-around.
Tue Jun 17 19:40:41 2003 Rein Klazes <rklazes@xs4all.nl>
* dirutil.c, ppp_fcs.c, pptp.c, pptp_gre.c, util.c, vector_test.c,
* pptp_ctrl.c, pptp_callmgr.c, vector.c : reformat code with
standard 4 spaced indents, uniform function headings and some
general tidying up. Patches have been separated in "diff -w"
invariant patches that should be safe and others that may be
not so safe.
Wed Jun 11 14:06:21 2003 Rein Klazes <rklazes@xs4all.nl>
* pptp_gre.c: When a timeout is specified in the select call
make it always non-zero. Making this call block makes it likely
that pppd will run before the select returns. This results in a
big reduction in transmitted ack-only packets (number down from
40% to 0.8% of received packets on my system).
Tue Jun 11 18:42:00 2003 James Cameron <quozl@us.netrek.org>
* pptp-linux-1.3.1 released.
Tue Jun 10 13:53:00 2003 Chris Wilson <chris@netservers.co.uk>
* pptp_callmgr.c: fixed a bug with call manager socket naming,
introduced since 1.2.0, which caused confusing problems when
trying to open more than one tunnel from the same machine.
Tue Jun 10 18:43:34 2003 James Cameron <quozl@us.netrek.org>
* pptp-linux-1.3.0 released.
Tue Jun 3 19:16:52 2003 James Cameron <quozl@us.netrek.org>
* pptp.8, pptp.c: change SIGHUP to SIGUSR1 for dumping stats.
Tue May 20 13:20:00 2003 Chris Wilson <chris@netservers.co.uk>
* pptp.c: rewrote command-line usage information, to increase
clarity and usefulness, and to describe various command-line
options which have been added recently.
Fri May 23 20:52:05 2003 Rein Klazes <rklazes@xs4all.nl>
* pptp_ctrl.c: increase the verbosity of the log message at the
receipt of a Call Disconnect Notification.
Mon May 12 16:56:14 2003 James Cameron <quozl@us.netrek.org>
* Makefile: don't install the manpage with execute permission,
swap LDFLAGS and LIBS so that one can say 'make LDFLAGS=-s' to
create a stripped versions of the executables, introduce the
optimization flag as a make variable, so that one can say 'make
DEBUG= OPTIMIZE=-O2 LDFLAGS=-s'. From: Peter Breitenlohner
Tue Apr 29 19:13:33 2003 James Cameron <quozl@us.netrek.org>
* Makefile (dist): remove CVS directory from distribution.
Reported by: Ola Lundqvist
Tue Apr 15 10:28:00 2003 Chris Wilson <chris@netservers.co.uk>
* pptp.c, pptp_gre.c, pptp_gre.h: Added GRE statistics counters
and RTT calculation, which can be dumped to the syslog by sending
a SIGHUP to the GRE-to-PPP gateway process.
Mon Apr 14 11:57:00 2003 Chris Wilson <chris@netservers.co.uk>
* pptp_gre.c: Fixed one case where an ACK could be immediately
followed by a data packet, they should be combined into a
single packet.
Sat Mar 8 2003 15:19:12 2003 Rein Klazes <rklazes@xs4all.nl>
* pptp_gre.c, pqueue.c: Actually copy the packet into a new entry
in the packet queue, fixing "unknown protocol" error messages;
Change the program logic making it obvious that there is not a
memory leak;
Restore the "buffering out-of-order packet" log messages, so we
have a chance to notice any more side effects.
Mon Feb 17 09:18:30 2003 James Cameron <quozl@us.netrek.org>
* pptp_callmgr.c, pptp.c, Makefile: compile call manager from
Makefile rather than include from pptp.c. From: Jan Pieter
<jp@jp.dhs.org>
Sat Feb 15 21:32:42 2003 James Cameron <quozl@us.netrek.org>
* pptp_ctrl.c, pptp_msg.h: move code out of .h file and into .c
file. From: Jan Pieter <jp@jp.dhs.org>
Sat Feb 15 17:34:38 2003 James Cameron <quozl@us.netrek.org>
* pptp.c: add include fixes for Apple MacOS X as contributed by an
anonymous donor.
Sat Feb 15 14:59:20 2003 James Cameron <quozl@us.netrek.org>
* pptp.c, pptp_callmgr.c, pptp_gre.c: add localbind option to
support multiple clients from separate alias IP addresses.
From: Yury Tarasievich, with contributions by Ed Marcotte.
Fri Feb 14 10:11:27 2003 James Cameron <quozl@us.netrek.org>
* pptp-linux-1.2.0 released.
Fri Feb 14 16:08:26 CET 2003 Rein Klazes <rklazes@xs4all.nl>
* pptp_ctrl.c, pptp_msg.h: tweak the outgoing call reply messages
once more. Print the error text that comes with the result code.
* pptp.c: close all unused file descriptors belonging to the pty.
* pptp_gre.c: Convert received acknowledgement numbers from network
to host order.
Mon Jan 20 11:46 2003 Chris Wilson <chris@netservers.co.uk>
* pqueue.c, pqueue.h: changed "expires" field of pqueue entry to a
struct timeval for microsecond accuracy (in theory =)
* pptp_gre.c: use queue head expiry time as the upper bound on how
long we block waiting for data from the network or pppd
* pptp.c: allow setting of packet timeout with sub-second
accuracy, print error message to stderr and exit if timeout out of
range
Mon Jan 13 10:28 2003 Chris Wilson <chris@netservers.co.uk>
* pqueue.c, pqueue.h: added freelist support for packet queue,
From: Kai Poitschke <kai@poitschke.de>. Should help to
prevent memory fragmentation and perhaps improve performance a
little.
* pqueue.c: wrap some log() statements with DEBUG_CMD, should
improve performance (thanks to Kai Poitschke)
* pptpd.c: bugfix for --log-string option: make a copy of the
string with strdup, because optarg will be destroyed
Wed Jan 15 14:16:27 2003 James Cameron <quozl@us.netrek.org>
* AUTHORS, DEVELOPERS, NEWS, README, TODO, USING: add or move CVS
header to tail.
* DEVELOPERS: change IRC server name to new alias.
* AUTHORS: change a few addresses.
* INSTALL: rewrite.
* README, USING: review and adjust, minor changes.
* Makefile (install): add MANDIR and man page.
Thu Jan 2 11:28:41 2003 James Cameron <quozl@us.netrek.org>
* pptp_gre.c: fix response to dropped packets. From: Rein Klazes.
Thu Jan 2 09:11:33 2003 James Cameron <quozl@us.netrek.org>
* pptp.8: the IP address should be before the option. From: Rein
Klazes
Mon Dec 30 15:57:48 2002 James Cameron <quozl@us.netrek.org>
* Makefile (install): add install target.
Mon Dec 9 08:52:56 2002 James Cameron <quozl@us.netrek.org>
* pptp_callmgr.c, pptp.c: close stderr after becoming daemon,
otherwise ssh sessions, CGI scripts, or other programs that start
pptp don't exit properly; they are held up until the pptp
processes terminate and close stderr.
Thu Nov 21 08:41:39 2002 James Cameron <quozl@us.netrek.org>
* pptp_gre.c: log return value from the read of the GRE socket as
a signed number as well.
Wed Nov 20 11:21:48 CET 2002 Rein Klazes <rklazes@xs4all.nl>
* pptp_gre.c: log return value from the read of the pty as a signed
number.
* pptp_ctrl.c: change the log message to clarify that error codes in a
outgoing call reply come from the server, not the client.
Wed Nov 20 16:07:30 2002 James Cameron <quozl@us.netrek.org>
* Makefile (dist): adjust distribution target to include new files
since prior use.
Wed Nov 20 15:17:12 2002 James Cameron <quozl@us.netrek.org>
* pptp_gre.c: hid many packet reordering log calls in an ifdef,
added a hint as to cause of EIO on read of the pty.
Fri Oct 11 15:44 BST 2002 Chris Wilson <chris@netservers.co.uk>
* pptp.c util.c util.h: added "--logstring" option to help identify
connections in syslog output where multiple connections are made
from the same host.
Wed Oct 02 10:31 BST 2002 Chris Wilson <chris@netservers.co.uk>
* pptp_gre.c pqueue.c: changed some "log" statements to "warn" to
reflect the severity of the condition, allowing much better filtering
* util.c: changed _warn to log at WARNING, and _fatal at CRIT level
* pptp_gre.c: disabled logging of individual accepted packets
* pptp_gre.c: removed a potential NULL pointer dereference crash
* pptp_gre.c: fixed the select-timeout check for packets in the queue
* pqueue.h: increased window size to 300 following testing
* pptp.c: added command-line parameter "--timeout" to set the
lost packet timeout
Fri Aug 30 09:55:05 CEST 2002 Rein Klazes <rklazes@xs4all.nl>
pptp_gre.c: Try to send more ACK's piggy backed on data packets.
Previously if there were any outstanding ACK's to be sent, the
program used a non-blocking select (timeout zero) to see if
any data packets are available. In most cases there will be none,
since the time passed since the last read is too short and an ACK
without data will be sent.
This change allows one outstanding ACK, for at most 0.5 second,
multiple outstanding ACK's are treated as before.
Tests show that this gives a big reduction in the number of
sent packets.
Fri Aug 30 09:15:35 CEST 2002 Rein Klazes <rklazes@xs4all.nl>
* pptp_gre.c: Sequence numbers of sent gre packets should start
with 1.
Mon Aug 26 10:56:42 CEST 2002 Rein Klazes <rklazes@xs4all.nl>
* pptp.c pptp_gre.c pptp_gre.h: added "--sync" option to work
in combination with the pppd sync option. In synchronous mode
checksum calculations and (un-)escaping of control characters
become unnecessary. This results in big CPU usage reduction.
Mon Aug 26 08:53:45 CEST 2002 Rein Klazes <rklazes@xs4all.nl>
* pptp.c: fix bug in command line options parsing (misplaced break
in switch statement).
Wed Aug 21 10:57:01 2002 James Cameron <quozl@us.netrek.org>
* pptp.c: add handler for SIGCHLD.
From: Peter Surda <shurdeek@panorama.sth.ac.at>
Thu Aug 15 09:30:00 2002 Chris Wilson <chris@netservers.co.uk>
* pqueue.h: increased window size following James' tests
* pptp_gre.c: check for errors while dequeueing packets
Wed Aug 14 20:02:39 2002 James Cameron <quozl@us.netrek.org>
* pptp.c, pptp_gre.c, pqueue.c: packet re-ordering bugfixes
following distributed testing:
- Moved daemon() call to run on GRE gateway process only, and not
if running as pppd pty
- Make select() timeout after 1 second if there is data in the
queue, to prevent the queue from having to wait forever
- Added log messages for accepting individual packets (noisy!)
and for timeouts on missing packets
- Fixed a bug with the packet queue (append to tail was broken)
- Removed unused code from pqueue.c
From: chris@netservers.co.uk
Wed Aug 14 11:14:05 2002 James Cameron <quozl@us.netrek.org>
* pqueue.c, pqueue.h, pptp_gre.c: major changes to support packet
re-ordering.
Queueing
Packets are added to the queue by decaps_gre if their sequence
number is higher than expected, but within the window. The default
window is defined as 30 packets.
Packets which are below the window (older than the most recent
packet read) or above the window (too far ahead) are discarded, to
protect against denial-of-service attacks.
Dequeueing
The new function dequeue_gre retrieves packets from the head of
the queue which are:
1. Next in sequence (unwrapped or wrapped)
2. Older than five seconds (assuming that the intermediate packets
have been lost by the network).
The function will continue to read packets from the head of the
queue until it finds one which doesn't match these criteria, and
then stop.
Limitations
There are some limitations with this patch:
- The receive window is hardcoded at 30 packets. I couldn't see
where to get the negotiated and/or current window size from.
- The timeout is hardcoded at 5 seconds. A packet which was
received and queued within the window, but which should have been
preceded by other packets which never appeared, will be accepted
anyway after this time (increasing the sequence number to its
own).
- There may be memory leaks or other bugs in the reordering code.
* pqueue.c, pqueue.h, Makefile (PPTP_OBJS, PPTP_DEPS): add two new
files to the pptp executable. pqueue.c implements the packet queue
used by the reordering code, and pqueue.h describes its public
interface. The queue is implemented as a linked list. This is
required for reordering.
* pptp.c: Add a new command-line option, --debug. Prevents pptp
from going into the background.
Change to call the daemon(3) function to change the current
directory and close the standard file descriptors. This prevents a
shell from hanging open if pptp is started remotely.
* Makefile (CFLAGS): reduce the optimisation level (gcc's -O flag)
to zero (none), to make debugging easier.
* pptp.c (get_ip_address): avoid reporting h_errno value.
From: chris@netservers.co.uk
Thu Jul 18 12:26:25 2002 James Cameron <quozl@us.netrek.org>
* pptp_gre.h, pptp_gre.c, pptp.c: bind the GRE socket early, by
calling the a function pptp_gre_bind. Also changed prototype of
pptp_gre_copy. Fixes ICMP Unreachable bug:
<1026868263.2855.67.camel@jander> 16th July 2002.
From: chris@netservers.co.uk
Thu May 30 18:28:02 2002 James Cameron <quozl@us.netrek.org>
* pptp_ctrl.c (pptp_call_open): do translation to network byte
order after limit checking of phone number.
From: staelin@hpl.hp.com
2002-05-13 08:14:40 Muli Ben-Yehuda <mulix@actcom.co.il>
* TODO: remove 'remove setjmp/longjmp' TODO item.
* pptp.c: change comment re volatile qualifiers.
* pptp_callmgr.c: remove unused function 'conn_callback' and
change comment re volatile qualifiers.
Thu Apr 4 09:34:10 2002 James Cameron <quozl@us.netrek.org>
* pptp_ctrl.c: correct spelling error.
From: Mary.Deck@COMPAQ.com
2002-03-30 13:13:52 mulix <mulix@actcom.co.il>
* USING: change URL for bezeq adsl howto.
* pptp.c: (get_ip_address): if the user runs 'pptp --quirks ...'
instead of 'pptp hostname', we'll get here and then give a verbose
error message.
Mon Mar 11 10:21:00 2002 mulix <mulix@actcom.co.il>
* Makefile (all): make config.h before making $(PPTP_BIN).
* Makefile (config.h): truncate the file if it exists before
inputing to it - '>' instead of '>>'
Mon Mar 11 12:48:16 2002 James Cameron <quozl@us.netrek.org>
* DEVELOPERS: add mailing lists.
* Makefile (CFLAGS): remove PPPD_BINARY and PPTP_LINUX_VERSION in
favour of a config.h file.
* Makefile (config.h): create config.h from Makefile variables
* Makefile (PPTP_DEPS): add config.h
* pptp.c: include config.h
* version.c: include config.h
* util.c (PROGRAM_NAME): no longer used by two programs, change
PROGRAM_NAME to default to pptp.
* Makefile (CFLAGS): remove -DPROGRAM_NAME
Fri Mar 8 11:56:00 2002 mulix <mulix@actcom.co.il>
* TODO: remove notes about compiler warnings, as all compiler
warnings are now gone.
* pptp.c (main): add volatile qualifier to some variables to
silence gcc warnings 'variable might be clobbered by longjmp or
vfork'. add note explaining why volatile and that it should be
removed when the longjmp is removed.
* pptp_callmgr.c (main): likewise.
* inststr.c (inststr): break up "ptr += strlen(++ptr)" which is
undefined behaviour into two expressions.
* pptp.c (main): initialize callmgr_sock to -1 since it might be
used uninitialized otherwise.
* pptp_ctrl.c (pptp_dispatch_ctrl_packet): #ifdef 0 two unused
variables referring to the current packet, which should not be
simply erased, as we might want to use them in the future.
* util.c: add missing #include.
Fri Mar 8 21:11:17 2002 James Cameron <quozl@us.netrek.org>
* DEVELOPERS: new file.
Fri Mar 8 10:12:28 2002 James Cameron <quozl@us.netrek.org>
* NEWS: convert to newest first format to comply with GNU Coding
Standards, The NEWS File.
Fri Mar 8 09:01:22 2002 James Cameron <quozl@us.netrek.org>
* pptp_ctrl.c (pptp_make_packet): Cisco PIX is generating a
non-complaint header with the reserved0 field not zero, causing
the connection to stop after 60 seconds.
From: Rein Klazes <rklazes@xs4all.nl>
Fri Mar 8 08:56:30 2002 James Cameron <quozl@us.netrek.org>
* TODO: add compiler warnings note.
* NEWS: propogate summary of ChangeLog.
* AUTHORS: add names from mailing list contributions.
From: Rein Klazes <rklazes@xs4all.nl>
* Makefile: remove pptp_callmgr binary
* debian/copyright: adjust pointer to current release.
* debian/rules, Makefile: remove pptp_callmgr binary now that pptp
forks and calls it without exec.
Sat Mar 2 04:04:37 2002 James Cameron <quozl@us.netrek.org>
* README: adopt new mailing lists and point to project web site.
* USING: include psuedo-tty activation instructions.
* Makefile: increment version, avoid clobbering editor backup
files on clean.
Fri Mar 1 12:13:03 2002 James Cameron <quozl@us.netrek.org>
* pptp_gre.c: move #include <sys/types.h> higher up
* pptp_gre.c, pptp_ctrl.c: change unsigned to unsigned int
* pptp.c: what we need from pty.h is in libutil.h for FreeBSD and
util.h for NetBSD (ideally this should be in autoconf)
* pptp.c: synchronisation changes
* orckit_quirks.c: #include <sys/types.h>
From: rhialto@azenomei.knuffel.net
Fri Nov 23 14:42:07 2001 James Cameron <quozl@us.netrek.org>
* USING: reformat, add version header.
Tue Nov 20 11:01:10 2001 mulix <mulix@actcom.co.il>
* AUTHORS: add mulix.
* USING: add paragraph on quirks support.
* orckit_quirks.c: remove debugging call, rename functions and
variables consistently.
* pptp.c: (usage) remove debugging print.
* pptp_ctrl.c: when calling quirks hooks, check their return
values and warn if an error occurs.
* pptp_quirks.c: orckit_atur3_start_ctrl_conn was renamed
orckit_atur3_start_ctrl_conn_hook.
From: mulix@actcom.co.il
Tue Nov 20 17:01:10 2001 James Cameron <quozl@us.netrek.org>
* orckit_quirks.c, orckit_quirks.h: add quirks handling for orckit
adsl modems.
* pptp_quirks.c, pptp_quirks.h: add generic quirks handling.
* Makefile (PPTP_DEPS, PPTP_OBJS, CALLMGR_OBJS, CALLMGR_DEPS): add
quirks sources and objects.
* pptp_ctrl.c: add pptp_set_link, add code to adjust packets
depending on quirks.
* pptp.c (usage, long_options, main): add --quirks command line
option.
From: mulix@actcom.co.il
Tue Nov 20 16:45:35 2001 James Cameron <quozl@us.netrek.org>
* pptp_gre.c: enhance error message for bad FCS.

87
DEVELOPERS Normal file
View File

@ -0,0 +1,87 @@
Developers Information
Mailing List
Subscribe to the pptpclient-devel mailing list if you intend to
contribute to this project. On this mailing list we discuss problems
and changes.
https://lists.sourceforge.net/lists/listinfo/pptpclient-devel
Patches
You may send patches by e-mail, direct or to the mailing list, or if
you have CVS commit rights, you may use them.
Developers have permission (and encouragement) to adjust more than the
file that they are submitting. Other files that may be adjusted are:
ChangeLog
documentation of changes at the code level.
NEWS
a history of changes as far as an end user is concerned.
AUTHORS
a list of people who want credit for contributions.
TODO
a list of things yet to be done.
See section two of Eric Raymond's Software Release Practice HOWTO for
some useful information on good patching practice.
http://www.linuxdoc.org/HOWTO/Software-Release-Practice-HOWTO/
CVS Commits Mailing List
Subscribe to the pptpclient-commits mailing list and you will receive
messages from the CVS server when another developer commits.
https://lists.sourceforge.net/lists/listinfo/pptpclient-commits
CVS Tags
There are two types of tags. Upstream source and release tags.
Upstream source tags are set by the person who brings in the upstream
version of ppp or ppp-mppe, and are not expected to move. This is
because we are not the authoritative maintainer for those two
packages; we're just generating a package ourselves.
Upstream source tags at the moment are
openssl-0_9_6
openssl-mppe-0_9_6
ppp-2_4_0
ppp-2_4_1
ppp-mppe-2_4_0
ppp-mppe-2_4_1
Release tags are set by the release engineer who makes the releases.
Only he is to move these tags.
Release tags at the moment are
pptp-linux-1_0_3-1
pptp-linux-1_1_0-rc1
pptp-linux-1_1_0-rc2
pptp-linux-1_1_0-rc3
ppp-mppe-2_4_0-3
ppp-mppe-2_4_1-rc1
Internet Relay Chat
Developers who use IRC on a regular basis are welcome to add the
project's channel to their list of autojoin channels.
Server: irc.freenode.net
Channel: #pptp
$Id: DEVELOPERS,v 1.4 2003/01/15 05:29:20 quozl Exp $

View File

@ -0,0 +1,23 @@
Call Manager is a single-threaded application.
It's easier that way.
Nothing blocks except a select() call.
The pptp code provides an fd_set for us to watch, and a function
to call to see if a given event pertains to the pptp code.
Each CALL connection goes in the exceptions set, and is watched for close.
We need a separate list of these, to check against the fd_set when
an event happens.
Writes get copied in a queue, and are only written if the select says we
can.
Reads go in another queue -- non-blocking! -- and messages are made from
the queue as we are able.
We register callbacks on significant events (any and all of them, if
we please) which can trigger a close on a user unix socket, for
example.
Nomenclature:
inet_read|write ... TCP port 1723 PPTP control connection
unix_read|write ... Call manager Unix socket to pppd/gre.

53
Documentation/DESIGN.PPTP Normal file
View File

@ -0,0 +1,53 @@
pptp called as:
pptp hostname [[pptp options] --] [pppd options]
The pptp program does:
gethostbyname([hostname]) to get ip number.
Try to open unix domain socket at /var/run/pptp/ip.num.ber.here.
If not found, launch call manager for that ip address.
Call manager opens unix domain socket at /var/run/pptp/ip.num.ber.here, does:
1) Open connection to the ip address using port 1723 protocol.
2) accept unix domain socket connection.
[wait for any pptp call request to this ip]
3) On receiving a connection, open CALL to ip.address using port 1723.
2) send callID over unix domain socket for gre encapsulation.
3) Keepalive the socket. When either side closes socket, send
call-close message to ip.address using port 1723.
4) on close of last call, send connection close using port 1723,
close the unix domain socket at /var/run/pptp/ip.num.ber.here,
and exit.
Once call manager is opened (fork when done to return status to parent),
the main process forks.
Parent) launch gre-copy task. Holds call manager socket.
Child) launch pppd with command-line options.
Killing any of the three threads should cleanly shutdown system. HOW?
Send pid of parent and child to call manager after fork over
Unix-domain socket.
Alternatively pptp may be launched by pppd. One advantage is that
many existing tools for managing serial ppp connections can be used with
pptp connections as well. Another is some pppd options can only be used
this way. In particular the options "persist" and "demand" may be of use.
Add the following option to your pppd options script:
pty "<insert.path.to>/pptp hostname --nolaunchpppd [--phone phone-nr]"
and start the connection like any other pppd connection. Note that
old versions of pppd may not support the pty option.
The following options are understood by pptp:
--phone phone-number
Specify the phone number for the connection. This is required
by a number of ADSL services.
--nolaunchpppd
Needed if pptp is to be launched by pppd. See above

56
Documentation/PORTING Normal file
View File

@ -0,0 +1,56 @@
pptp uses very few linux-specific features, and should be easily
portable to most Unix systems.
Two things to watch:
1)
The code in pty.[ch] to find a free pty/tty pair. This was
conceptually borrowed from the xterm sources, which need to
do more or less the same thing. *But* the xterm sources had
a heck of a lot more system-specific #defines to cover all
the eccentric unix variants out there. If you are porting
this code to a non-unix system, I would recommend downloading
the xterm sources to find out how pty.[ch] should look for
your system. Xterm is in the standard X distribution, or
you can download SRRMs from ftp.redhat.com.
Configure the xterm sources for your machine, and then preprocess
main.c with these configuration options. E.g. I did:
[cananian@cananian xterm-sb_right-ansi-3d]# make main.o
rm -f main.o
gcc -c -O2 -fno-strength-reduce -m486 -I/usr/X11R6/include
-Dlinux -D__i386__ -D_POSIX_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE
-DX_LOCALE -DFUNCPROTO=15 -DNARROWPROTO -DUTMP -DUSE_TTY_GROUP
-DOSMAJORVERSION=2 -DOSMINORVERSION=0 main.c
So the appropriate preprocessing command would be:
[cananian@cananian xterm-sb_right-ansi-3d]# gcc -E -O2
-fno-strength-reduce -m486 -I/usr/X11R6/include -Dlinux -D__i386__
-D_POSIX_SOURCE -D_BSD_SOURCE -D_SVID_SOURCE -DX_LOCALE
-DFUNCPROTO=15 -DNARROWPROTO -DUTMP -DUSE_TTY_GROUP
-DOSMAJORVERSION=2 -DOSMINORVERSION=0 main.c > main.CPP
Grok through the sources to figure out how the ptys are allocated on
your machine. I suspect many people will want to look carefully at
the function pty_search(), but there are architectures that have
other, built-in, functions for doing the same thing.
Add the code to pty.[ch] with the proper #ifdefs, mail a patch back
to me at <cananian@alumni.princeton.edu> and you're good to go!
2) The pptp_gre_copy function opens an IP protocol socket with:
s = socket(AF_INET, SOCK_RAW, PPTP_PROTO);
where PPTP_PROTO is #define'd in the code to be 47. I *think* that
this should work across Unix variants, but if your system has a
different method for opening a non-TCP, raw-IP-protocol-47 socket,
then you'll have to make some changes here, and perhaps in
decaps_gre and encaps_gre as well.
OK. Those are the only two potential non-portabilities I can think
of. I should really be using automake/autoconf, of course, as well.
--Scott 15Dec1997
--------------------------------------------------------------------
C. Scott Ananian <cananian@alumni.princeton.edu>

45
INSTALL Normal file
View File

@ -0,0 +1,45 @@
Installation Instructions - Brief
1. install pppd (with MPPE if you require it),
2. if pppd is not in /usr/sbin, edit Makefile, variable PPPD,
3. 'make'
4. 'make install'
Installation Instructions - Detailed
1. install PPP, and make sure it is working.
On most distributions, use the package called ppp or pppd.
If your PPTP server requires MPPE, make sure the pppd program
has been built with MPPE and MS-CHAP support. PPP from
version 2.4.2 onwards has this support. PPP may require
kernel support for MPPE, which may require patching your
kernel.
2. verify that the pppd program is in the /usr/sbin/ directory.
On some distributions, it is in /usr/bin, or somewhere else.
If it isn't in the default directory, edit the Makefile, and
change the PPPD variable to point at the pppd program.
You may even want to run a separate pppd program with MPPE
support.
3. compile
Type 'make'. This should generate the 'pptp' executable.
4. install binaries
Type 'make install' to have the program and the manual page
installed.
Further information
http://pptpclient.sourceforge.net/
$Id: INSTALL,v 1.2 2003/01/15 05:29:20 quozl Exp $

175
Makefile Normal file
View File

@ -0,0 +1,175 @@
# $Id: Makefile,v 1.51 2011/11/29 22:05:07 quozl Exp $
VERSION=1.10.0
RELEASE=
#################################################################
# CHANGE THIS LINE to point to the location of binaries
PPPD = /usr/sbin/pppd
# Solaris
# PPPD = /usr/bin/pppd
IP = /bin/ip
#################################################################
BINDIR=$(DESTDIR)/usr/sbin
MANDIR=$(DESTDIR)/usr/share/man/man8
PPPDIR=$(DESTDIR)/etc/ppp
CC = gcc
RM = rm -f
OPTIMIZE= -O -Wuninitialized
DEBUG = -g
INCLUDE =
# CFLAGS = -Wall $(OPTIMIZE) $(DEBUG) $(INCLUDE)
# Solaris
# CFLAGS += -D_XPG4_2 -D__EXTENSIONS__
LIBS = -lutil
# Solaris 10
# LIBS = -lnsl -lsocket -lresolv
# Solaris Nevada build 14 or above
# LIBS = -lnsl -lsocket
# LDFLAGS =
PPTP_BIN = pptp
PPTP_OBJS = pptp.o pptp_gre.o ppp_fcs.o \
pptp_ctrl.o dirutil.o vector.o \
util.o version.o test-redirections.o \
pptp_quirks.o orckit_quirks.o pqueue.o pptp_callmgr.o routing.o \
pptp_compat.o
PPTP_DEPS = pptp_callmgr.h pptp_gre.h ppp_fcs.h util.h test-redirections.h \
pptp_quirks.h orckit_quirks.h config.h pqueue.h routing.h
all: config.h $(PPTP_BIN) pptpsetup.8
$(PPTP_BIN): $(PPTP_OBJS) $(PPTP_DEPS)
$(CC) -o $(PPTP_BIN) $(PPTP_OBJS) $(LDFLAGS) $(LIBS)
pptpsetup.8: pptpsetup
pod2man --section=8 $? > $@
config.h:
( \
echo "/* text added by Makefile target config.h */"; \
echo "#define PPTP_LINUX_VERSION \"$(VERSION)$(RELEASE)\""; \
echo "#define PPPD_BINARY \"$(PPPD)\""; \
echo "#define IP_BINARY \"$(IP)\"" \
) > config.h
vector_test: vector_test.o vector.o
$(CC) -o vector_test vector_test.o vector.o
./vector_test
clean:
$(RM) *.o config.h pptpsetup.8
clobber: clean
$(RM) $(PPTP_BIN) vector_test
distclean: clobber
test: vector_test
install:
mkdir -p $(BINDIR)
install -o root -m 555 pptp $(BINDIR)
install -o root -m 555 pptpsetup $(BINDIR)
mkdir -p $(MANDIR)
install -m 644 pptp.8 $(MANDIR)
install -m 644 pptpsetup.8 $(MANDIR)
mkdir -p $(PPPDIR)
install -m 644 options.pptp $(PPPDIR)
uninstall:
$(RM) $(BINDIR)/pptp $(MANDIR)/pptp.8
dist: clobber
$(RM) pptp-$(VERSION)$(RELEASE).tar.gz
$(RM) -r pptp-$(VERSION)
mkdir pptp-$(VERSION)
cp --recursive ChangeLog Makefile *.c *.h options.pptp pptp.8 \
pptpsetup Documentation AUTHORS COPYING INSTALL NEWS \
README DEVELOPERS TODO USING PROTOCOL-SECURITY \
pptp-$(VERSION)/
$(RM) -r pptp-$(VERSION)/CVS pptp-$(VERSION)/*/CVS
tar czf pptp-$(VERSION)$(RELEASE).tar.gz pptp-$(VERSION)
$(RM) -r pptp-$(VERSION)
md5sum pptp-$(VERSION)$(RELEASE).tar.gz
deb:
chmod +x debian/rules
fakeroot dpkg-buildpackage -us -uc
mv ../pptp_$(VERSION)-0_i386.deb .
WEB=~/public_html/external/mine/pptp/pptpconfig
release:
cp pptp_$(VERSION)-0_i386.deb $(WEB)
cd $(WEB);make
# The following include file dependencies were generated using
# "makedepend -w0 *.c", then manually removing out of tree entries.
# DO NOT DELETE
dirutil.o: dirutil.h
orckit_quirks.o: pptp_msg.h
orckit_quirks.o: pptp_compat.h
orckit_quirks.o: pptp_options.h
orckit_quirks.o: pptp_ctrl.h
orckit_quirks.o: util.h
ppp_fcs.o: ppp_fcs.h
ppp_fcs.o: pptp_compat.h
pptp.o: config.h
pptp.o: pptp_callmgr.h
pptp.o: pptp_gre.h
pptp.o: pptp_compat.h
pptp.o: version.h
pptp.o: util.h
pptp.o: pptp_quirks.h
pptp.o: pptp_msg.h
pptp.o: pptp_ctrl.h
pptp.o: pqueue.h
pptp.o: pptp_options.h
pptp_callmgr.o: pptp_callmgr.h
pptp_callmgr.o: pptp_ctrl.h
pptp_callmgr.o: pptp_compat.h
pptp_callmgr.o: pptp_msg.h
pptp_callmgr.o: dirutil.h
pptp_callmgr.o: vector.h
pptp_callmgr.o: util.h
pptp_callmgr.o: routing.h
pptp_compat.o: pptp_compat.h
pptp_compat.o: util.h
pptp_ctrl.o: pptp_msg.h
pptp_ctrl.o: pptp_compat.h
pptp_ctrl.o: pptp_ctrl.h
pptp_ctrl.o: pptp_options.h
pptp_ctrl.o: vector.h
pptp_ctrl.o: util.h
pptp_ctrl.o: pptp_quirks.h
pptp_gre.o: ppp_fcs.h
pptp_gre.o: pptp_compat.h
pptp_gre.o: pptp_msg.h
pptp_gre.o: pptp_gre.h
pptp_gre.o: util.h
pptp_gre.o: pqueue.h
pptp_gre.o: test-redirections.h
pptp_quirks.o: orckit_quirks.h
pptp_quirks.o: pptp_options.h
pptp_quirks.o: pptp_ctrl.h
pptp_quirks.o: pptp_compat.h
pptp_quirks.o: pptp_msg.h
pptp_quirks.o: pptp_quirks.h
pqueue.o: util.h
pqueue.o: pqueue.h
routing.o: routing.h
routing.o: config.h
test-redirections.o: util.h
test-redirections.o: test-redirections.h
util.o: util.h
vector.o: pptp_ctrl.h
vector.o: pptp_compat.h
vector.o: vector.h
vector_test.o: vector.h
vector_test.o: pptp_ctrl.h
vector_test.o: pptp_compat.h
version.o: config.h

180
NEWS Normal file
View File

@ -0,0 +1,180 @@
Release 1.10.0: (18th January 2018)
- assign copyright of contributed pptpsetup and routing.c to FSF,
- remove inststr in favour of prctrl PR_SET_NAME,
- vector tests; include in make, fix code rot, fix return status,
- pqueue; include missing sys/types.h,
- pptpsetup; prevent world-readable peers file, use three-argument
append, allow password trailing spaces, split prints to
chap-secrets, allow passwords with quotes, use absolute path to
pptp,
- remove uid from ip route get output; iproute2-4.10 and later may
emit uid,
Release 1.9.0: (29th November 2016)
- close a memory leak in pqueue,
- avoid spurious error about /bin/ip on FreeBSD,
- fix compiler warnings,
- avoid clobbering heap (RHBZ #1183627),
- fix use after free in call close request handler,
- make clean to clean pptpsetup.8 (Debian #831032),
- add --missing-window option (Debian #680455, Ubuntu #681617),
- randomise call-id (Debian #721963),
- replace gethostbyname(3) with getaddrinfo(3),
- fix typo in pptp_ctrl manpage,
- place pptpsetup manpage in correct section,
- don't set build flags; use defaults,
- remove pptpsetup.8 from source as it is generated,
- fix for (null) in "pptp: GRE-to-PPP gateway on (null)".
Release 1.8.0: (23rd October 2013)
- options file, fix option documentation and links [Howarth]
- fix many warnings [Howarth]
- fix parallel build failure [Howarth]
- fix call disconnect notify [Howarth]
- add --nohostroute option to disable routing calls [Lamparter]
- add --rtmark option for Linux policy routing [Lamparter]
- move free of conn struct out of main loop [Cameron]
- avoid using conn struct after it is freed [Keijser]
- correct response to call disconnect notify [Shen]
- avoid superfluous MPPE capability checks in pptpsetup [Howarth]
- retain permissions on chap-secrets, closes RH BZ #492090 [Howarth]
- compilation fixes for older distributions of Linux [Howarth]
- port routing change feature for Solaris [Voronin]
- add IP_BINARY [Cameron]
- add include file build dependencies [Cameron]
Release 1.7.2: (14th May 2008)
- port for Solaris 10/11 [Voronin]
- make copyright and license clearer [Cameron/Ananian]
- add packet reordering test code for pptpd testing [Cameron]
- ignore transient send errors [Adda]
- fix flaw in return status check of select in GRE pipe (possibly
fixes Debian Bug #427586) [Cameron]
- add route to PPTP server [Cameron]
- remove non-free reference documentation [Cameron]
- fix quoting and pppd options [Lundqvist]
- pptpsetup script with man page (Debian Bug #167216) [Ferraz]
Release 1.7.1: (13th February 2006)
- use prctl(2) to set process name [Cameron]
- add --version option [Cameron]
- remove superfluous sigset [Cameron/Gono]
- default options file to not require MPPE (#166394) [Howarth]
- add PROTOCOL-SECURITY discussion [Cameron/Mueller]
Release 1.7.0: (27th July 2005)
- silently discard packets not for the call [Cameron/Jenkins]
- adopt sigpipe for use with SIGALRM on control connection [Wolter/Cameron]
- fixes known valgrind heap violations in 1.6.0 [Cameron/Thorne]
- properly report control connection echo reply loss [Wolter]
Release 1.6.0: (18th February 2005)
- fix double-free on stop control connection reply [Kivity]
- add --idle-wait option [Cameron]
- fix segfault on fatal connection error [Kivity]
- prevent a possible signal race [Kivity]
- prevent kill of init [Shurdeek]
- portability fix for non-Linux systems [Quinot]
- rename package from pptp-linux to pptp [Cameron]
Release 1.5.0: (22nd June 2004)
- fix statistics when buffering disabled [Wilson]
- do not inherit the GRE socket [Cameron]
- fix a case of non-shutdown of call manager [Klazes]
- add --nobuffer option to eliminate all buffering of packets [Wilson]
- fix corruption of command line as shown by ps [Howarth]
- fix CPU loop after pppd killed [Cameron]
- fix compile for ARM architecture [Hopf]
- add documentation for command-line options [Wilson]
- do not hang when a connection is refused [McCurdy]
- better describe a cause of EMSGSIZE [Cameron]
Release 1.4.0: (2nd January 2004)
- support options before hostname [Wilson]
- defer OCRQ until after SCCRP [Cameron]
- include uninstall target [Pieter]
- only issue a warning if sync mode is different to pppd [Klazes]
- reformat and tidy code [Klazes]
- reduce transmitted ack-only packets from 40% to 0.8% [Klazes]
Release 1.3.1: (11th June 2003)
- fixed bug introduced since 1.2.0 that prevented simultaneous tunnels.
Release 1.3.0: (10th June 2003)
- rewrite command usage text.
- increase call disconnect notification log message verbosity.
- inherit more make command line options.
- remove execute permissions on man page.
- fixed inefficient acknowledgement immediately followed by data packet.
- added statistics for link quality monitoring.
- remove include of callmgr, do separate compile.
- remove duplicate messages caused by code in header file.
- compilation fixes for Apple MacOS X.
- support multiple clients on alias IP addresses.
Release 1.2.0: (14th February 2003)
- subsecond packet timeout to improve performance on fast links.
- rewrite INSTALL.
- add man page to install target.
- fix response to dropped packets.
- fix man page, address must be before options.
- adopt man page contributed by Thomas Quinot.
- close stderr to prevent holding open ssh sessions.
- minor hint added in case of EIO on read() of pty.
- support synchronous HDLC ppp encoding. Synchronous mode results in an
important improvement of the CPU efficiency.
- handle out-of-order packets arriving on the GRE socket by buffering.
- bind GRE socket early to prevent ICMP Unreachable response by client.
Release 1.1.0: (20th March 2002)
- New release engineer.
- allow activation as a psuedo-tty child process from pppd.
This allows on demand pptp links or automatically reconnect.
- ADSL modem quirks handler by mulix@actcom.co.il.
Workarounds for Orckit ADSL modem.
- workaround for Cisco PIX connection drop after 60 seconds.
- enhance bad FCS error message.
- ported to FreeBSD and NetBSD.
- integrated call manager into pptp binary.
- many bugfixes improving stability.
Release 1.0.3: (7th May 2001)
- New maintaining team.
- Various bug fixes from the Debian package and FreeBSD port.
- Incorporate patch to support erroneous return code with
Alcatel ADSL 1000 modems.
- Fix incorrect call id error.
- New command line option: --phone (specify phone number).
(Needed by the Dutch Mxstream ADSL service.)
Contributed by Rein Klazes <rklazes@xs4all.nl>
Release 1.0.2:
- Fixed some warnings.
- glibc patches by Christoph Lameter <christoph@lameter.com>
- Race condition fix by Gordon Chaffee <chaffee@HOME.COM>
Release 1.0.1:
- Added versioning information to sources and makefile.
- Bugfixes to pptp_ctrl.c.
Release 1.0.0:
- This is the first public release of the pptp-linux package.
$Id: NEWS,v 1.71 2011/11/29 22:05:07 quozl Exp $

88
PROTOCOL-SECURITY Normal file
View File

@ -0,0 +1,88 @@
Protocol Security
Summary
by Peter Mueller
PPTP is known to be a faulty protocol. The designers of the protocol,
Microsoft, recommend not to use it due to the inherent risks. Lots of
people use PPTP anyway due to ease of use, but that doesn't mean it is
any less hazardous. The maintainers of PPTP Client and Poptop
recommend using OpenVPN (SSL based) or IPSec instead.
(Posted on [1]2005-08-10 to the [2]mailing list)
_________________________________________________________________
Why not use PPTP?
by James Cameron
The point to point tunneling protocol (PPTP) is not secure enough for
some information security policies.
It's the nature of the MSCHAP V2 authentication, how it can be broken
trivially by capture of the datastream, and how MPPE depends on the
MSCHAP tokens for cryptographic keys. MPPE is also only 128-bit,
reasonably straightforward to attack, and the keys used at each end
are the same, which lowers the effort required to succeed. The obvious
lack of two-factor authentication, instead relying on a single
username and password, is also a risk. The increasing use of domestic
wireless systems makes information capture more likely.
However, that doesn't mean people don't accept the risks. There are
many corporations and individuals using PPTP with full knowledge of
these risks. Some use mitigating controls, and some don't.
Many people seem to judge the security of a protocol by the
availability of the implementation, the ease of installation, or the
level of documentation on our web site. Improving the documentation is
the purpose of this web site, and we aren't doing that in order to say
anything about the risks of the software! Any judgement of security
should be rigorously applied to the design and implementation alone.
PPTP on Linux, and Microsoft's PPTP, both implement fixes for
vulnerabilities that were detected years ago in Microsoft's PPTP. But
there remain the design vulnerabilities that cannot be fixed without
changing the design. The changes needed would break interoperability.
We can't change the Linux PPTP design, because it would stop working
with Microsoft PPTP. They can't change their design, because it would
stop working with all the other components out there, such as Nortel
and Cisco, embedded routers, ADSL modems and their own Windows
installed base.
The only option then is to deprecate the product and promote the
replacement. Microsoft promote something else. Our choice for Open
Source systems is OpenVPN or IPsec.
Level of acceptance isn't a good indicator of risk either. Some have
said that the shipping of MSCHAP V2, MPPE and PPTP in Linux
distributions is an indication of design security, but that's not the
reason. It's for interoperability. As an example, see how Linux
distributions still ship telnet, ftp, and rsh, even though these
components are insecure because they reveal the password in cleartext
in the network packets. The same can be said of many other components
and packages.
Our recommendations are;
1. do not implement PPTP between open source systems, because there's
no justification, better security can be had from OpenVPN or
IPsec,
2. do not implement PPTP servers unless the justification is that the
clients must not have to install anything to get going (Microsoft
PPTP is included already), and be aware of the risks of
information interception,
3. do not implement PPTP clients unless the justification is that the
server only provides PPTP, and there's nothing better that can be
used, and again be aware of the risks of information interception.
(Posted on [3]2005-08-10 to the [2]mailing list)
References
1. http://marc.theaimsgroup.com/?l=poptop-server&m=112369621702624&w=2
2. http://pptpclient.sourceforge.net/contact.phtml#list
3. http://marc.theaimsgroup.com/?l=poptop-server&m=112365342910897&w=2

49
README Normal file
View File

@ -0,0 +1,49 @@
pptp
pptp is an implementation of the PPTP protocol for Linux and
other Unix systems.
Copyright (C) 2000 Free Software Foundation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
You can find notes on installing in the file INSTALL, usage notes in
the file USING, design notes in the Documentation directory, and the
standards documents used to implement pptp can be found in the
Reference directory.
New versions and additional documentation can be found on the PPTP
Client project page, at http://pptpclient.sourceforge.net/
Discussion of this code occurs on the mailing list for the PPTP Client
project on SourceForge. To subscribe, visit the project's mailing
lists page, or
http://lists.sourceforge.net/lists/listinfo/pptpclient-devel
Discussion of this code used to occur on the mailing list
pptp@debs.fuller.edu, subscribe by sending "subscribe" in the body on
an email to pptp-request@debs.fuller.edu, or look at
http://debs.fuller.edu. Christoph Lameter was the list organizer.
Re-organization and patches are of course greatly welcomed.
See the file TODO.
James Cameron <james.cameron@hp.com> (maintainer, release engineer)
C. Scott Ananian <cananian@alumni.princeton.edu> (original author)
$Id: README,v 1.6 2011/11/10 23:31:27 quozl Exp $

115
TODO Normal file
View File

@ -0,0 +1,115 @@
18th September 2006
https://sourceforge.net/tracker/?func=detail&atid=407155&aid=1560433&group_id=33063
Feature request, add code to attempt multiple IPs in a round-robin DNS
rotation.
12th September 2006
https://sourceforge.net/tracker/?func=detail&atid=407152&aid=1556506&group_id=33063
Add call-id as quirk or command-line option.
13th February 2006
pty write may block, which prevents read, according to patch #502930 on
SourceForge. Generally a lack of flow control. We don't implement flow
control well.
8th April 2005
On Thu, Apr 07, 2005 at 07:36:41AM -0700, Roark Hennessy wrote:
> I find in order to get the tunnel working I have to do a
> route add -host <target_vpn_addr> gateway <my-netgear-wireless-router> dev
+ethN
> Can this be done automatically in the config somewhere?
Not everybody needs this in order to get the tunnel working, it depends
on the configuration of the server, and it is problematic calculating
the correct route to add. However, the GUI PPTP client (pptpconfig)
does this automatically, and when done unnecessarily it seems harmless.
I'll take a patch that implements the same thing in C within pptp, so
that people who don't use the GUI get it done for them.
Here's what the pptpconfig.php program does;
- the IP address of the PPTP server is obtained from the name, using
gethostbyname(),
- the command "ip route get $ip | head -1" is executed, where $ip is the
IP address determined above, and the result of the command is stored;
it is a route specification of the path to the server before the
tunnel is started,
- in routing_start(), an "ip route add" command is done using the route
specification obtained above,
- when the tunnel is shutdown, an "ip route del" command is done using
the same route specification.
I would prefer that the patch implements this by embedding the
equivalent syscalls within the pptp program, rather than use system() or
popen() to execute the /usr/sbin/ip program.
I would also prefer that there be a command line option for disabling
the feature.
--
10th March 2005
- call manager is not being reused as it was designed to be; if a
tunnel is started within a minute of a tunnel being stopped, it does
not succeed; symptom is LCP ConfReq's without any traffic from the
server.
--
- finish --max-echo-wait
11th August 2004
- add two configurable timeouts for echo generation and echo reply timeout,
requested by Tobias Brox.
- ship .spec with tarball.
13th February 2004
- timeout connect earlier, with option to extend timeout.
20th May 2003
- GRE stats to a pipe or shared memory, for GUI to use
15th February 2003
- pptp.8 update man page for new options
- pptp.c long_options array should use NULL for second last arg, not 0
- pptp.c use getopt_long more simply, e.g. set flags in option array
1st May 2002
- log failure of write() to raw socket, as Ryan Murray
<rmurray@debian.org> has encountered an EPERM situation that was not
being logged.
12th February 2002
- clean up -T errors in pptp-command,
23rd December 2000
Things to do:
Autoconf/automake this beastie.
Fix do_gre_copy semantics to properly handle multiple calls.
Like the call manager, there should only be one gre-copy process
per connection. This process needs to funnel packets to different
output tty's, though, depending on the call-id embedded in the
GRE encapsulation. pptp.c must then be modified to use an
already-existing gre-copy process in the same way it uses an
already-existing call manager.
$Id: TODO,v 1.29 2006/09/18 01:50:05 quozl Exp $

98
USING Normal file
View File

@ -0,0 +1,98 @@
Usage Notes
pptp is started as a psuedo-tty child process using pppd's pty option:
pppd call provider [pppd-options] \
pty "/usr/sbin/pptp hostname --nolaunchpppd [pptp-options]"
where hostname is the host name or IP address of the PPTP server.
pptp can also start pppd itself:
pptp hostname [pptp-options] [pppd-options]
Note the unusual order of arguments, the hostname comes before the
pptp options, and the pppd options come last.
So, for example:
pptp my.pptp.host debug name cananian \
remotename ntdialup 172.18.0.2:172.18.0.3
route add -net 172.18.0.0 netmask 255.255.0.0 gw 172.18.0.3
You will see three pptp-related processes in your process list: a call
manager, a GRE/PPP en/decapsulator, and pppd. To shut down the pptp
connection, kill the pppd process.
NOTE THAT PPTP MUST BE RUN AS ROOT. This is so that it can generate
GRE packets using a raw socket.
Most trouble with pptp will probably be due to incorrect pppd
configuration. Be sure you thoroughly understand MS-CHAP support in
pppd. Use the 'debug' option to pppd to log connection information;
this will help you trouble-shoot the pppd side of pptp.
See the project web site for diagnosis assistance.
QUIRKS HANDLING:
Some ADSL providers and some ADSL hardware are buggy or not conforming
to the RFC, and require special handling. To this end, pptp supports
a 'quirks' mechanism. Currently, only '--quirks BEZEQ_ISRAEL' is
defined, for connecting to Bezeq (the Israeli phone company) ADSL
service.
Only *some* of the equipment used by Bezeq needs this option, but even
the equipment that does not need it works fine with it. If you use
Bezeq, you probably want the '--quirks BEZEQ_ISRAEL' switch.
More information on Bezeq's ADSL service can be found at
http://vipe.technion.il/~mulix/adsl-howto.txt and
http://damyen.technion.ac.il/~dani/adsl-howto.txt.
TESTING MULTIPLE TUNNELS:
For testing of PPTP servers, the client can be used to establish
multiple tunnels from multiple IP addresses. The addresses must be
routable; this is something you'd do on a local area network.
1. use an address pool on a concentrator.
2. write an ip-up script (e.g. /etc/ppp/ip-up.local or /etc/ppp/ip-up.d)
#!/bin/sh
export PATH=/sbin:/usr/sbin:/bin:/usr/bin
REALDEVICE=$1
PEERADDR=$6
ifconfig ${REALDEVICE} dstaddr ${PEERADDR}
The script performs an "ifconfig pppx dstaddr xx.xx.xx.xx" where
xx.xx.xx.xx is the private address of the concentrator so that the
routing works without having to do iptables or ipchains. The address
used is given on the pptp command line.
3. create distinct source interfaces with:
ifconfig eth0:n xx.xx.xx.xx netmask yy.yy.yy.yy
Where "n" is the alias interface number, "xx.xx.xx.xx" is the new
address, and "yy.yy.yy.yy" is the network mask.
4. connect with
pptp concentrator --bind xx.xx.xx.xx name \
xx remotename yy ipparam yy.yy.yy.yy
^ (private address of concentrator).
Where "xx.xx.xx.xx" is the address of the source interface, "xx" is
the local name of the tunnel, "yy" is the remote name of the tunnel,
and "yy.yy.yy.yy" is the private address of the concentrator. This is
passed to the ip-up script as the sixth argument.
See also the following test scripts;
test-multiple-tunnels-1.sh creates multiple source interfaces
test-multiple-tunnels-2.sh creates multiple tunnels
$Id: USING,v 1.6 2003/02/15 04:32:50 quozl Exp $

68
dirutil.c Normal file
View File

@ -0,0 +1,68 @@
/* dirutil.c ... directory utilities.
* C. Scott Ananian <cananian@alumni.princeton.edu>
*
* $Id: dirutil.c,v 1.2 2003/06/17 17:25:47 reink Exp $
*/
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include "dirutil.h"
/* Returned malloc'ed string representing basename */
char *basenamex(char *pathname)
{
char *dup = strdup(pathname);
char *ptr = strrchr(stripslash(dup), '/');
if (ptr == NULL) return dup;
ptr = strdup(ptr+1);
free(dup);
return ptr;
}
/* Return malloc'ed string representing directory name (no trailing slash) */
char *dirname(char *pathname)
{
char *dup = strdup(pathname);
char *ptr = strrchr(stripslash(dup), '/');
if (ptr == NULL) { free(dup); return strdup("."); }
if (ptr == dup && dup[0] == '/') ptr++;
*ptr = '\0';
return dup;
}
/* In-place modify a string to remove trailing slashes. Returns arg.
* stripslash("/") returns "/";
*/
char *stripslash(char *pathname) {
int len = strlen(pathname);
while (len > 1 && pathname[len - 1] == '/')
pathname[--len] = '\0';
return pathname;
}
/* ensure dirname exists, creating it if necessary. */
int make_valid_path(char *dir, mode_t mode)
{
struct stat st;
char *tmp = NULL, *path = stripslash(strdup(dir));
int retval;
if (stat(path, &st) == 0) { /* file exists */
if (S_ISDIR(st.st_mode)) { retval = 1; goto end; }
else { retval = 0; goto end; } /* not a directory. Oops. */
}
/* Directory doesn't exist. Let's make it. */
/* Make parent first. */
if (!make_valid_path(tmp = dirname(path), mode)) { retval = 0; goto end; }
/* Now make this 'un. */
if (mkdir(path, mode) < 0) { retval = 0; goto end; }
/* Success. */
retval = 1;
end:
if (tmp != NULL) free(tmp);
if (path != NULL) free(path);
return retval;
}

14
dirutil.h Normal file
View File

@ -0,0 +1,14 @@
/* dirutil.h ... directory utilities.
* C. Scott Ananian <cananian@alumni.princeton.edu>
*
* $Id: dirutil.h,v 1.1 2000/12/23 08:19:51 scott Exp $
*/
/* Returned malloc'ed string representing basename */
char *basenamex(char *pathname);
/* Return malloc'ed string representing directory name (no trailing slash) */
char *dirname(char *pathname);
/* In-place modify a string to remove trailing slashes. Returns arg. */
char *stripslash(char *pathname);
/* ensure dirname exists, creating it if necessary. */
int make_valid_path(char *dirname, mode_t mode);

59
options.pptp Normal file
View File

@ -0,0 +1,59 @@
###############################################################################
# $Id: options.pptp,v 1.4 2012/08/30 21:34:13 quozl Exp $
#
# Sample PPTP PPP options file /etc/ppp/options.pptp
# Options used by PPP when a connection is made by a PPTP client.
# This file can be referred to by an /etc/ppp/peers file for the tunnel.
# Changes are effective on the next connection. See "man pppd".
#
# You are expected to change this file to suit your system. As
# packaged, it requires PPP 2.4.2 or later from http://ppp.samba.org/
# and the kernel MPPE module available from the CVS repository also on
# http://ppp.samba.org/, which is packaged for DKMS as kernel_ppp_mppe.
###############################################################################
# Lock the port
lock
# Authentication
# We don't need the tunnel server to authenticate itself
noauth
# We won't do PAP, EAP, CHAP, or MSCHAP, but we will accept MSCHAP-V2
# (you may need to remove these refusals if the server is not using MPPE)
refuse-pap
refuse-eap
refuse-chap
refuse-mschap
# Compression
# Turn off compression protocols we know won't be used
nobsdcomp
nodeflate
# Encryption
# (There have been multiple versions of PPP with encryption support,
# choose which of the following sections you will use. Note that MPPE
# requires the use of MSCHAP-V2 during authentication)
#
# Note that using PPTP with MPPE and MSCHAP-V2 should be considered
# insecure:
# http://marc.info/?l=pptpclient-devel&m=134372640219039&w=2
# https://github.com/moxie0/chapcrack/blob/master/README.md
# http://technet.microsoft.com/en-us/security/advisory/2743314
# http://ppp.samba.org/ the PPP project version of PPP by Paul Mackarras
# ppp-2.4.2 or later with MPPE only, kernel module ppp_mppe.o
# If the kernel is booted in FIPS mode (fips=1), the ppp_mppe.ko module
# is not allowed and PPTP-MPPE is not available.
# {{{
# Require MPPE 128-bit encryption
#require-mppe-128
# }}}
# http://mppe-mppc.alphacron.de/ fork from PPP project by Jan Dubiec
# ppp-2.4.2 or later with MPPE and MPPC, kernel module ppp_mppe_mppc.o
# {{{
# Require MPPE 128-bit encryption
#mppe required,stateless
# }}}

86
orckit_quirks.c Normal file
View File

@ -0,0 +1,86 @@
/* orckit_quirks.c ...... fix quirks in orckit adsl modems
* mulix <mulix@actcom.co.il>
*
* $Id: orckit_quirks.c,v 1.4 2011/12/19 07:13:30 quozl Exp $
*/
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include "pptp_msg.h"
#include "pptp_options.h"
#include "pptp_ctrl.h"
#include "util.h"
/* return 0 on success, non zero otherwise */
int
orckit_atur3_build_hook(struct pptp_out_call_rqst* packet)
{
unsigned int name_length = 10;
struct pptp_out_call_rqst fixed_packet = {
PPTP_HEADER_CTRL(PPTP_OUT_CALL_RQST),
0, /* hton16(call->callid) */
0, /* hton16(call->sernum) */
hton32(PPTP_BPS_MIN), hton32(PPTP_BPS_MAX),
hton32(PPTP_BEARER_DIGITAL), hton32(PPTP_FRAME_ANY),
hton16(PPTP_WINDOW), 0, hton16(name_length), 0,
{'R','E','L','A','Y','_','P','P','P','1',0}, {0}
};
if (!packet)
return -1;
memcpy(packet, &fixed_packet, sizeof(*packet));
return 0;
}
/* return 0 on success, non zero otherwise */
int
orckit_atur3_set_link_hook(struct pptp_set_link_info* packet,
int peer_call_id)
{
struct pptp_set_link_info fixed_packet = {
PPTP_HEADER_CTRL(PPTP_SET_LINK_INFO),
hton16(peer_call_id),
0,
0xffffffff,
0xffffffff};
if (!packet)
return -1;
memcpy(packet, &fixed_packet, sizeof(*packet));
return 0;
}
/* return 0 on success, non 0 otherwise */
int
orckit_atur3_start_ctrl_conn_hook(struct pptp_start_ctrl_conn* packet)
{
struct pptp_start_ctrl_conn fixed_packet = {
{0, 0, 0, 0 , 0}, /* we'll set the header later */
hton16(PPTP_VERSION), 0, 0,
hton32(PPTP_FRAME_ASYNC), hton32(PPTP_BEARER_ANALOG),
hton16(0) /* max channels */,
hton16(0x6021),
{'R','E','L','A','Y','_','P','P','P','1',0}, /* hostname */
{'M','S',' ','W','i','n',' ','N','T',0} /* vendor */
};
if (!packet)
return -1;
/* grab the header from the original packet, since we dont
know if this is a request or a reply */
memcpy(&fixed_packet.header, &packet->header, sizeof(struct pptp_header));
/* and now overwrite the full packet, effectively preserving the header */
memcpy(packet, &fixed_packet, sizeof(*packet));
return 0;
}

27
orckit_quirks.h Normal file
View File

@ -0,0 +1,27 @@
/* orckit_quirks.h ...... fix quirks in orckit adsl modems
* mulix <mulix@actcom.co.il>
*
* $Id: orckit_quirks.h,v 1.2 2001/11/23 03:42:51 quozl Exp $
*/
#ifndef INC_ORCKIT_QUIRKS_H_
#define INC_ORCKIT_QUIRKS_H_
#include "pptp_options.h"
#include "pptp_ctrl.h"
#include "pptp_msg.h"
/* return 0 on success, non zero otherwise */
int
orckit_atur3_build_hook(struct pptp_out_call_rqst* packt);
/* return 0 on success, non zero otherwise */
int
orckit_atur3_set_link_hook(struct pptp_set_link_info* packet,
int peer_call_id);
/* return 0 on success, non zero otherwise */
int
orckit_atur3_start_ctrl_conn_hook(struct pptp_start_ctrl_conn* packet);
#endif /* INC_ORCKIT_QUIRKS_H_ */

116
ppp_fcs.c Normal file
View File

@ -0,0 +1,116 @@
/* Fast Frame Check Sequence (FCS) Implementation, for HDLC-like framing of
* PPP. Adapted by C. Scott Ananian <cananian@alumni.princeton.edu>
* from RFC1662:
*
* C.2. 16-bit FCS Computation Method
*
* The following code provides a table lookup computation for
* calculating the Frame Check Sequence as data arrives at the
* interface. This implementation is based on [7], [8], and [9].
*
* [7] Perez, "Byte-wise CRC Calculations", IEEE Micro, June 1983.
*
* [8] Morse, G., "Calculating CRC's by Bits and Bytes", Byte,
* September 1986.
*
* [9] LeVan, J., "A Fast CRC", Byte, November 1987.
*
* $Id: ppp_fcs.c,v 1.2 2003/06/17 17:25:47 reink Exp $
*/
#include <sys/types.h>
#include <assert.h>
#include "ppp_fcs.h"
#define ASSERT(x) assert(x)
/*
* u16 represents an unsigned 16-bit number. Adjust the typedef for
* your hardware.
*/
typedef u_int16_t u16;
/*
* FCS lookup table as calculated by the table generator.
*/
static u16 fcstab[256] = {
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};
#ifndef PPPINITFCS16
#define PPPINITFCS16 0xffff /* Initial FCS value */
#endif
#ifndef PPPGOODFCS16
#define PPPGOODFCS16 0xf0b8 /* Good final FCS value */
#endif
/*
* Calculate a new fcs given the current fcs and the new data.
*/
u16 pppfcs16(u16 fcs, void *_cp, int len)
{
register unsigned char *cp = (unsigned char *)_cp;
/* don't worry about the efficiency of these asserts here. gcc will
* recognise that the asserted expressions are constant and remove them.
* Whether they are usefull is another question.
*/
ASSERT(sizeof (u16) == 2);
ASSERT(((u16) -1) > 0);
while (len--)
fcs = (fcs >> 8) ^ fcstab[(fcs ^ *cp++) & 0xff];
return (fcs);
}
#if 0
/*
* How to use the fcs
*/
tryfcs16(cp, len)
register unsigned char *cp;
register int len;
{
u16 trialfcs;
/* add on output */
trialfcs = pppfcs16( PPPINITFCS16, cp, len );
trialfcs ^= 0xffff; /* complement */
cp[len] = (trialfcs & 0x00ff); /* least significant byte first */
cp[len+1] = ((trialfcs >> 8) & 0x00ff);
/* check on input */
trialfcs = pppfcs16( PPPINITFCS16, cp, len + 2 );
if ( trialfcs == PPPGOODFCS16 )
printf("Good FCS\n");
}
#endif

12
ppp_fcs.h Normal file
View File

@ -0,0 +1,12 @@
/* ppp_fcs.h ... header file for PPP-HDLC FCS
* C. Scott Ananian <cananian@alumni.princeton.edu>
*
* $Id: ppp_fcs.h,v 1.2 2008/02/19 05:05:03 quozl Exp $
*/
#include "pptp_compat.h"
#define PPPINITFCS16 0xffff /* Initial FCS value */
#define PPPGOODFCS16 0xf0b8 /* Good final FCS value */
u_int16_t pppfcs16(u_int16_t fcs, void *cp, int len);

240
pptp.8 Normal file
View File

@ -0,0 +1,240 @@
.\" SH section heading
.\" SS subsection heading
.\" LP paragraph
.\" IP indented paragraph
.\" TP hanging label
.TH PPTP 8
.\" NAME should be all caps, SECTION should be 1-8, maybe w/ subsection
.\" other parms are allowed: see man(7), man(1)
.SH NAME
pptp \- PPTP driver
.SH SYNOPSIS
.B pptp
.I "<pptp-server-IP> <pptp-options> [ppp-options] ..."
.SH "DESCRIPTION"
.LP
.B pptp
establishes the client side of a Virtual Private Network (VPN) using
the Point-to-Point Tunneling Protocol (PPTP). Use this program to
connect to an employer's PPTP based VPN, or to certain cable and ADSL
service providers.
.LP
By default, \fBpptp\fR establishes the PPTP call to the PPTP server,
and then starts an instance of \fBpppd\fR to manage the data transfer.
However, \fBpptp\fR can also be run as a connection manager within
\fBpppd\fR.
.SH OPTIONS
.LP
The first non\-option argument on the \fBpptp\fR command line must be the host
name or IP address of the PPTP server.
.LP
All long options (starting with "\-\-")
are interpreted as pptp options, and a fatal error occurs if an
unrecognised option is used.
.LP
All command\-line arguments which do not start
with "\-" are interpreted as ppp options, and passed as is to \fBpppd\fR unless
\fB\-\-nolaunchpppd\fR is given.
.TP
.B \-\-phone <number>
Pass <number> to remote host as phone number
.TP
.B \-\-nolaunchpppd
Do not launch
.B pppd
but use stdin as the network connection. Use this flag when including
.B pptp
as a
.B pppd
connection process using the
.B pty
option. See EXAMPLES.
.TP
.B \-\-quirks <quirk>
Work around a buggy PPTP implementation, adopts special case handling for
particular PPTP servers and ADSL modems.
Currently recognised values are BEZEQ_ISRAEL only
.TP
.B \-\-debug
Run in foreground (for debugging with gdb)
.TP
.B \-\-sync
Enable Synchronous HDLC (pppd must use it too)
.TP
.B \-\-timeout <secs>
Time to wait for reordered packets (0.01 to 10 secs)
.TP
.B \-\-nobuffer
Completely disables buffering and reordering of packets.
Any \-\-timeout specified will be ignored.
.TP
.B \-\-idle-wait <secs>
Time to wait before sending a control connection echo request.
The RFC2637 default is 60 seconds.
.TP
.B \-\-max-echo-wait <secs>
Time to wait for an echo reply before closing the control connection.
The RFC2637 default is 60 seconds.
.TP
.B \-\-logstring <name>
Use <name> instead of 'anon' in syslog messages
.TP
.B \-\-localbind <addr>
Bind to specified IP address instead of wildcard
.TP
.B \-\-rtmark <n>
Use specified policy routing mark for all packets.
This causes both the TCP control connection's packets as well as the
GRE packets to bear the given policy routing / netfilter mark. This
can be used with
.I ip rule
(from iproute2) to use a separate routing table for the pptp client.
(requires root privileges or the CAP_NET_ADMIN capability.)
.TP
.B \-\-nohostroute
Do not configure a host route pointing towards the PPTP server.
(cf. ROUTING below)
.TP
.B \-\-loglevel <level>
Sets the debugging level (0=low, 1=default, 2=high)
.TP
.B \-\-test-type <n>
Enable packet reordering tests that damage the integrity of the packet
stream to the server. Use this only when testing servers. Zero is
the default, and means that packets are sent in the correct order. A
value of one (1) causes a single swap between two packets, such that
the sequence numbers might be 1 2 3 4 6 5 7 8 9. A value of two (2)
causes ten packets to be buffered, then sent out of order but
ascending, such that the sequence numbers might be 1 2 3 4 16 6 7 8 9
10 11 12 13 14 15 17 18 19 20. A value of three (3) causes ten
packets to be buffered, then sent in the reverse order, like this; 1 2
3 4 16 15 14 13 12 11 10 9 8 7 6 5 17 18 19 20.
.TP
.B \-\-test-rate <n>
Sets the number of packets to pass before causing a reordering test.
Default is 100. Has no effect if test-type is zero. The result of
test types 2 and 3 are undefined if this value is less than ten.
.SH "ROUTING"
When PPTP is used in conjunction with a default route on top of the
tunnel (or just any route encompassing the PPTP server),
the mechanics of routing would cause the PPTP packets themselves
to be routed over the tunnel. This would result in an encapsulation
loop, destroying connectivity.
.B pptp
by default works around this by looking up the route towards the
PPTP server at startup and configures a host route with that data.
This essentially "freezes" routing for PPTP packets at the startup
configuration. This behaviour can be disabled with
.B --nohostroute
if undesired (like when using
.B --rtmark
to implement policy routing).
.B NB:
the route added by
.B pptp
is currently not deleted at exit!
.SH "QUIRKS"
.TP
.B BEZEQ_ISRAEL
modifies packets to interoperate with Orckit ADSL modems on the BEZEQ
network in Israel.
.SH "EXAMPLES"
.B Connection to a Microsoft Windows VPN Server
.BR
pppd noauth nobsdcomp nodeflate require\-mppe\-128 name domain\\\\\\\\username remotename PPTP pty "pptp 10.0.0.5 \-\-nolaunchpppd"
.PP
Note that the \fBchap\-secrets\fR file used by \fBpppd\fR must include an entry for domain\\\\username
.SH "STATISTICS"
The pptp process collects statistics when sending and receiving
GRE packets. They are intended to be useful for debugging poor PPTP
performance and for general monitoring of link quality. The statistics
are cumulative since the pptp process was started.
.PP
The statistics can be viewed by sending a SIGUSR1 signal to the
"GRE-to-PPP Gateway" process, which will cause it to dump them
to the system logs (at the LOG_NOTICE level). A better way to present
the statistics to applications is being sought (e.g. SNMP?).
.PP
The following statistics are collected at the time of writing (April 2003):
.TP
.B rx accepted
the number of GRE packets successfully passed to PPP
.TP
.B rx lost
the number of packets never received, and presumed lost in the network
.TP
.B rx under win
the number of packets which were duplicates or had old sequence numbers
(this might be caused by a packet-reordering network if your reordering
timeout is set too low)
.TP
.B rx over win
the number of packets which were too far ahead in the sequence to be
reordered (might be caused by loss of more than 300 packets in a row)
.TP
.B rx buffered
the number of packets which were slightly ahead of sequence, and were
either buffered for reordering, or if buffering is disabled, accepted
immediately (resulting in the intermediate packets being discarded).
.TP
.B rx OS errors
the number of times where the operating system reported an error when
we tried to read a packet
.TP
.B rx truncated
the number of times we received a packet which was shorter than the
length implied by the GRE header
.TP
.B rx invalid
the number of times we received a packet which had invalid or unsupported
flags set in the header, wrong version, or wrong protocol.
.TP
.B rx acks
the number of pure acknowledgements received (without data). Too many
of these will waste bandwidth, and might be solved by tuning the remote host.
.TP
.B tx sent
the number of GRE packets sent with data
.TP
.B tx failed
the number of packets we tried to send, but the OS reported an error
.TP
.B tx short
the number of times the OS would not let us write a complete packet
.TP
.B tx acks
the number of times we sent a pure ack, without data
.TP
.B tx oversize
the number of times we couldn't send a packet because it was over
PACKET_MAX bytes long
.TP
.B round trip
the estimated round-trip time in milliseconds
.SH "SEE ALSO"
.IR pppd (8)
.PP
Documentation in
.IR /usr/share/doc/pptp
.SH AUTHOR
This manual page was written by James Cameron
<james.cameron@hp.com> from text contributed by Thomas Quinot
<thomas@debian.org>, for the Debian GNU/Linux system.
The description of the available statistics was written by Chris Wilson
<chris@netservers.co.uk>. Updates for the Debian distribution by
Ola Lundqvist <opal@debian.org>.

614
pptp.c Normal file
View File

@ -0,0 +1,614 @@
/*
an implementation of the PPTP protocol
Copyright (C) 2000 Free Software Foundation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
pptp.c ... client shell to launch call managers, data handlers, and
the pppd from the command line.
*/
#include <sys/types.h>
#include <sys/socket.h>
#if defined(__FreeBSD__)
#include <libutil.h>
#elif defined(__NetBSD__) || defined(__OpenBSD__)
#include <util.h>
#elif defined(__APPLE__)
#include <util.h>
#elif defined (__SVR4) && defined (__sun)
#else
#include <pty.h>
#endif
#ifdef USER_PPP
#include <fcntl.h>
#endif
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <syslog.h>
#include <unistd.h>
#include <signal.h>
#include <setjmp.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/param.h>
#if defined(__APPLE__)
#include "getopt.h"
#else
#include <getopt.h>
#endif
#include <limits.h>
#include "config.h"
#include "pptp_callmgr.h"
#include "pptp_gre.h"
#include "version.h"
#if defined(__linux__)
#include <sys/prctl.h>
#endif
#include "util.h"
#include "pptp_quirks.h"
#include "pqueue.h"
#include "pptp_options.h"
#include "pptp_compat.h"
#ifndef PPPD_BINARY
#define PPPD_BINARY "pppd"
#endif
int syncppp = 0;
int log_level = 1;
int disable_buffer = 0;
int test_type = 0;
int test_rate = 100;
int missing_window = MISSING_WINDOW;
struct in_addr get_ip_address(char *name);
int open_callmgr(struct in_addr inetaddr, char *phonenr, int argc,char **argv,char **envp, int pty_fd, int gre_fd);
void launch_callmgr(struct in_addr inetaddr, char *phonenr, int argc,char **argv,char **envp);
int get_call_id(int sock, pid_t gre, pid_t pppd,
u_int16_t *call_id, u_int16_t *peer_call_id);
void launch_pppd(char *ttydev, int argc, char **argv);
/*** print usage and exit *****************************************************/
void usage(char *progname)
{
fprintf(stderr,
"%s\n"
"Copyright (C) 2000 Free Software Foundation\n\n"
"This program comes with ABSOLUTELY NO WARRANTY; for details see source.\n"
"This is free software, and you are welcome to redistribute it under certain\n"
"conditions; see source for details.\n\n"
"Usage:\n"
" %s <hostname> [<pptp options>] [[--] <pppd options>]\n"
"\n"
"Or using pppd's pty option: \n"
" pppd pty \"%s <hostname> --nolaunchpppd <pptp options>\"\n"
"\n"
"Available pptp options:\n"
" --version Display version number and exit\n"
" --phone <number> Pass <number> to remote host as phone number\n"
" --nolaunchpppd Do not launch pppd, for use as a pppd pty\n"
" --quirks <quirk> Work around a buggy PPTP implementation\n"
" Currently recognised values are BEZEQ_ISRAEL only\n"
" --debug Run in foreground (for debugging with gdb)\n"
" --sync Enable Synchronous HDLC (pppd must use it too)\n"
" --timeout <secs> Time to wait for reordered packets (0.01 to 10 secs)\n"
" --nobuffer Disable packet buffering and reordering completely\n"
" --idle-wait Time to wait before sending echo request\n"
" --max-echo-wait Time to wait before giving up on lack of reply\n"
" --logstring <name> Use <name> instead of 'anon' in syslog messages\n"
" --localbind <addr> Bind to specified IP address instead of wildcard\n"
#ifdef SO_MARK
" --rtmark <n> Use specified policy routing mark for all packets\n"
#endif
" --nohostroute Do not add host route towards <hostname>\n"
" --loglevel <level> Sets the debugging level (0=low, 1=default, 2=high)\n"
" --test-type <type> Damage the packet stream by reordering\n"
" --test-rate <n> Do the test every n packets\n"
" --missing-window <n> Enable 'missing window' validation and set packet\n"
" polerance (300=default, 6000=recommended)\n",
version, progname, progname);
log("%s called with wrong arguments, program not started.", progname);
exit(1);
}
#if defined (__SVR4) && defined (__sun)
struct in_addr localbind = { .s_addr = INADDR_ANY };
#else
struct in_addr localbind = { INADDR_NONE };
#endif
int rtmark = 0;
int nohostroute = 0;
static int signaled = 0;
/*** do nothing signal handler ************************************************/
void do_nothing(int sig)
{
/* do nothing signal handler. Better than SIG_IGN. */
signaled = sig;
}
sigjmp_buf env;
/*** signal handler ***********************************************************/
void sighandler(int sig __attribute__ ((unused)))
{
siglongjmp(env, 1);
}
/*** report statistics signal handler (SIGUSR1) *******************************/
void sigstats(int sig __attribute__ ((unused)))
{
syslog(LOG_NOTICE, "GRE statistics:\n");
#define LOG(name,value) syslog(LOG_NOTICE, name "\n", stats .value)
LOG("rx accepted = %d", rx_accepted);
LOG("rx lost = %d", rx_lost);
LOG("rx under win = %d", rx_underwin);
LOG("rx over win = %d", rx_overwin);
LOG("rx buffered = %d", rx_buffered);
LOG("rx OS errors = %d", rx_errors);
LOG("rx truncated = %d", rx_truncated);
LOG("rx invalid = %d", rx_invalid);
LOG("rx acks = %d", rx_acks);
LOG("tx sent = %d", tx_sent);
LOG("tx failed = %d", tx_failed);
LOG("tx short = %d", tx_short);
LOG("tx acks = %d", tx_acks);
LOG("tx oversize = %d", tx_oversize);
LOG("round trip = %d usecs", rtt);
#undef LOG
}
/*** main *********************************************************************/
/* TODO: redesign to avoid longjmp/setjmp. Several variables here
have a volatile qualifier to silence warnings from gcc < 3.0.
Remove the volatile qualifiers if longjmp/setjmp are removed.
*/
int main(int argc, char **argv, char **envp)
{
struct in_addr inetaddr;
volatile int callmgr_sock = -1;
char ttydev[PATH_MAX];
char *pty_name;
int pty_fd, tty_fd, gre_fd, rc;
volatile pid_t parent_pid, child_pid;
u_int16_t call_id, peer_call_id;
char buf[128];
int pppdargc;
char **pppdargv;
char phonenrbuf[65]; /* maximum length of field plus one for the trailing
* '\0' */
char * volatile phonenr = NULL;
volatile int launchpppd = 1, debug = 0;
while(1){
/* structure with all recognised options for pptp */
static struct option long_options[] = {
{"phone", 1, 0, 0},
{"nolaunchpppd", 0, 0, 0},
{"quirks", 1, 0, 0},
{"debug", 0, 0, 0},
{"sync", 0, 0, 0},
{"timeout", 1, 0, 0},
{"logstring", 1, 0, 0},
{"localbind", 1, 0, 0},
{"loglevel", 1, 0, 0},
{"nobuffer", 0, 0, 0},
{"idle-wait", 1, 0, 0},
{"max-echo-wait", 1, 0, 0},
{"version", 0, 0, 0},
{"test-type", 1, 0, 0},
{"test-rate", 1, 0, 0},
{"rtmark", 1, 0, 0},
{"nohostroute", 0, 0, 0},
{"missing-window", 1, 0, 0},
{0, 0, 0, 0}
};
int option_index = 0;
int c;
c = getopt_long (argc, argv, "", long_options, &option_index);
if (c == -1) break; /* no more options */
switch (c) {
case 0:
if (option_index == 0) { /* --phone specified */
strncpy(phonenrbuf,optarg,sizeof(phonenrbuf));
phonenrbuf[sizeof(phonenrbuf) - 1] = '\0';
phonenr = phonenrbuf;
} else if (option_index == 1) {/* --nolaunchpppd specified */
launchpppd = 0;
} else if (option_index == 2) {/* --quirks specified */
if (set_quirk_index(find_quirk(optarg)))
usage(argv[0]);
} else if (option_index == 3) {/* --debug */
debug = 1;
} else if (option_index == 4) {/* --sync specified */
syncppp = 1;
} else if (option_index == 5) {/* --timeout */
float new_packet_timeout = atof(optarg);
if (new_packet_timeout < 0.0099 ||
new_packet_timeout > 10) {
fprintf(stderr, "Packet timeout %s (%f) out of range: "
"should be between 0.01 and 10 seconds\n",
optarg, new_packet_timeout);
log("Packet timeout %s (%f) out of range: should be"
"between 0.01 and 10 seconds", optarg,
new_packet_timeout);
exit(2);
} else {
packet_timeout_usecs = new_packet_timeout * 1000000;
}
} else if (option_index == 6) {/* --logstring */
log_string = strdup(optarg);
} else if (option_index == 7) {/* --localbind */
if (inet_pton(AF_INET, optarg, (void *) &localbind) < 1) {
fprintf(stderr, "Local bind address %s invalid\n",
optarg);
log("Local bind address %s invalid\n", optarg);
exit(2);
}
} else if (option_index == 8) { /* --loglevel */
log_level = atoi(optarg);
if (log_level < 0 || log_level > 2)
usage(argv[0]);
} else if (option_index == 9) { /* --nobuffer */
disable_buffer = 1;
} else if (option_index == 10) { /* --idle-wait */
int x = atoi(optarg);
if (x < 0) {
fprintf(stderr, "--idle-wait must not be negative\n");
log("--idle-wait must not be negative\n");
exit(2);
} else {
idle_wait = x;
}
} else if (option_index == 11) { /* --max-echo-wait */
int x = atoi(optarg);
if (x < 0) {
fprintf(stderr, "--max-echo-wait must not be negative\n");
log("--max-echo-wait must not be negative\n");
exit(2);
} else {
max_echo_wait = x;
}
fprintf(stderr, "--max-echo-wait ignored, not yet implemented\n");
} else if (option_index == 12) { /* --version */
fprintf(stdout, "%s\n", version);
exit(0);
} else if (option_index == 13) { /* --test-type */
test_type = atoi(optarg);
} else if (option_index == 14) { /* --test-rate */
test_rate = atoi(optarg);
} else if (option_index == 15) { /* --rtmark */
#ifdef SO_MARK
rtmark = atoi(optarg);
#else
fprintf(stderr, "--rtmark support was missing when "
"this binary was compiled.\n");
exit(2);
#endif
} else if (option_index == 16) { /* --nohostroute */
nohostroute = 1;
} else if (option_index == 17) { /* --missing window */
int x = atoi(optarg);
if (x <= 0) {
fprintf(stderr, "--missing-window must be integer "
"greater than zero\n");
log("--missing-window must be integer "
"greater than zero\n");
exit(2);
} else if (x < 300) {
fprintf(stderr, "--missing-window is set very low: "
"default=300, recommended=6000 - proceeding");
log("--missing-window is set very low: "
"default=300, recommended=6000 - proceeding\n");
} else {
fprintf(stderr, "--missing-window validation is active "
"and set to: %d\n", x);
log("--missing-window validation is active "
"and set to: %d\n", x);
missing_window = x;
}
}
break;
case '?': /* unrecognised option */
/* fall through */
default:
usage(argv[0]);
}
}
/* at least one argument is required */
if (argc <= optind)
usage(argv[0]);
/* Get IP address for the hostname in argv[1] */
inetaddr = get_ip_address(argv[optind]);
optind++;
/* Find the ppp options, extract phone number */
pppdargc = argc - optind;
pppdargv = argv + optind;
log("The synchronous pptp option is %sactivated\n", syncppp ? "" : "NOT ");
/* Now we have the peer address, bind the GRE socket early,
before starting pppd. This prevents the ICMP Unreachable bug
documented in <1026868263.2855.67.camel@jander> */
gre_fd = pptp_gre_bind(inetaddr);
if (gre_fd < 0) {
fatal("Cannot bind GRE socket, aborting.");
}
/* Find an open pty/tty pair. */
if(launchpppd){
rc = openpty (&pty_fd, &tty_fd, ttydev, NULL, NULL);
if (rc < 0) {
fatal("Could not find free pty.");
}
/* fork and wait. */
signal(SIGUSR1, do_nothing); /* don't die */
signal(SIGCHLD, do_nothing); /* don't ignore SIGCHLD */
parent_pid = getpid();
switch (child_pid = fork()) {
case -1:
fatal("Could not fork pppd process");
case 0: /* I'm the child! */
close (tty_fd);
signal(SIGUSR1, SIG_DFL);
child_pid = getpid();
break;
default: /* parent */
close (pty_fd);
/*
* There is still a very small race condition here. If a signal
* occurs after signaled is checked but before pause is called,
* things will hang.
*/
if (!signaled) {
pause(); /* wait for the signal */
}
if (signaled == SIGCHLD)
fatal("Child process died");
launch_pppd(ttydev, pppdargc, pppdargv); /* launch pppd */
perror("Error");
fatal("Could not launch pppd");
}
} else { /* ! launchpppd */
pty_fd = tty_fd = STDIN_FILENO;
/* close unused file descriptor, that is redirected to the pty */
close(STDOUT_FILENO);
child_pid = getpid();
parent_pid = 0; /* don't kill pppd */
}
do {
/*
* Open connection to call manager (Launch call manager if necessary.)
*/
callmgr_sock = open_callmgr(inetaddr, phonenr, argc, argv, envp,
pty_fd, gre_fd);
/* Exchange PIDs, get call ID */
} while (get_call_id(callmgr_sock, parent_pid, child_pid,
&call_id, &peer_call_id) < 0);
/* Send signal to wake up pppd task */
if (launchpppd) {
kill(parent_pid, SIGUSR1);
sleep(2);
/* become a daemon */
if (!debug && daemon(0, 0) != 0) {
perror("daemon");
}
} else {
/* re-open stderr as /dev/null to release it */
file2fd("/dev/null", "wb", STDERR_FILENO);
}
pty_name = ttyname(pty_fd);
snprintf(buf, sizeof(buf), "pptp: GRE-to-PPP gateway on %s",
pty_name ? pty_name : "(null)");
#ifdef PR_SET_NAME
rc = prctl(PR_SET_NAME, "pptpgw", 0, 0, 0);
if (rc != 0) perror("prctl");
#endif
if (sigsetjmp(env, 1)!= 0) goto shutdown;
signal(SIGINT, sighandler);
signal(SIGTERM, sighandler);
signal(SIGKILL, sighandler);
signal(SIGCHLD, sighandler);
signal(SIGUSR1, sigstats);
/* Do GRE copy until close. */
pptp_gre_copy(call_id, peer_call_id, pty_fd, gre_fd);
shutdown:
/* on close, kill all. */
if(launchpppd)
kill(parent_pid, SIGTERM);
close(pty_fd);
close(callmgr_sock);
exit(0);
}
/*** get the ipaddress coming from the command line ***************************/
struct in_addr get_ip_address(char *name)
{
int rc;
struct in_addr retval;
struct addrinfo hints, *ai;
memset(&hints, '\0', sizeof(hints));
hints.ai_family = AF_INET;
#if defined(__linux__) || defined(__FreeBSD__)
hints.ai_flags = AI_ADDRCONFIG; /* Unknown in OpenBSD. */
#endif
if ( (rc = getaddrinfo(name, NULL, &hints, &ai)) )
fatal("getaddrinfo(): %s", gai_strerror(rc));
if (ai->ai_addr->sa_family != AF_INET) /* Should never happen. */
fatal("Host '%s' possesses no IPv4 address", name);
memcpy(&retval.s_addr,
&(((struct sockaddr_in *) ai->ai_addr)->sin_addr.s_addr),
sizeof(retval.s_addr));
freeaddrinfo(ai);
return retval;
}
/*** start the call manager ***************************************************/
int open_callmgr(struct in_addr inetaddr, char *phonenr, int argc, char **argv,
char **envp, int pty_fd, int gre_fd)
{
/* Try to open unix domain socket to call manager. */
union {
struct sockaddr a;
struct sockaddr_un u;
} where;
const int NUM_TRIES = 3;
int i, fd;
pid_t pid;
int status;
/* Open socket */
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
fatal("Could not create unix domain socket: %s", strerror(errno));
}
/* Make address */
callmgr_name_unixsock(&where.u, inetaddr, localbind);
for (i = 0; i < NUM_TRIES; i++) {
if (connect(fd, &where.a, sizeof(where)) < 0) {
/* couldn't connect. We'll have to launch this guy. */
unlink (where.u.sun_path); /* FIXME: potential race condition */
/* fork and launch call manager process */
switch (pid = fork()) {
case -1: /* failure */
fatal("fork() to launch call manager failed.");
case 0: /* child */
{
close (fd);
/* close the pty and gre in the call manager */
close(pty_fd);
close(gre_fd);
launch_callmgr(inetaddr, phonenr, argc, argv, envp);
}
default: /* parent */
waitpid(pid, &status, 0);
if (WEXITSTATUS(status) != 0)
fatal("Call manager exited with error %d", status);
break;
}
sleep(1);
}
else return fd;
}
close(fd);
fatal("Could not launch call manager after %d tries.", i);
return -1; /* make gcc happy */
}
/*** call the call manager main ***********************************************/
void launch_callmgr(struct in_addr inetaddr, char *phonenr, int argc __attribute__ ((unused)),
char**argv,char**envp)
{
char *my_argv[3] = { argv[0], inet_ntoa(inetaddr), phonenr };
char buf[128];
snprintf(buf, sizeof(buf), "pptp: call manager for %s", my_argv[1]);
#ifdef PR_SET_NAME
int rc;
rc = prctl(PR_SET_NAME, "pptpcm", 0, 0, 0);
if (rc != 0) perror("prctl");
#endif
exit(callmgr_main(3, my_argv, envp));
}
/*** exchange data with the call manager *************************************/
/* XXX need better error checking XXX */
int get_call_id(int sock, pid_t gre, pid_t pppd,
u_int16_t *call_id, u_int16_t *peer_call_id)
{
u_int16_t m_call_id, m_peer_call_id;
/* write pid's to socket */
/* don't bother with network byte order, because pid's are meaningless
* outside the local host.
*/
int rc;
rc = write(sock, &gre, sizeof(gre));
if (rc != sizeof(gre))
return -1;
rc = write(sock, &pppd, sizeof(pppd));
if (rc != sizeof(pppd))
return -1;
rc = read(sock, &m_call_id, sizeof(m_call_id));
if (rc != sizeof(m_call_id))
return -1;
rc = read(sock, &m_peer_call_id, sizeof(m_peer_call_id));
if (rc != sizeof(m_peer_call_id))
return -1;
/*
* XXX FIXME ... DO ERROR CHECKING & TIME-OUTS XXX
* (Rhialto: I am assuming for now that timeouts are not relevant
* here, because the read and write calls would return -1 (fail) when
* the peer goes away during the process. We know it is (or was)
* running because the connect() call succeeded.)
* (James: on the other hand, if the route to the peer goes away, we
* wouldn't get told by read() or write() for quite some time.)
*/
*call_id = m_call_id;
*peer_call_id = m_peer_call_id;
return 0;
}
/*** execvp pppd **************************************************************/
void launch_pppd(char *ttydev, int argc, char **argv)
{
char *new_argv[argc + 4];/* XXX if not using GCC, hard code a limit here. */
char str_pppd[] = PPPD_BINARY;
char str_direct[] __attribute__ ((unused)) = "-direct";
char str_38400[] = "38400";
int i = 0, j;
new_argv[i++] = str_pppd;
#ifdef USER_PPP
new_argv[i++] = str_direct;
/* ppp expects to have stdin connected to ttydev */
if ((j = open(ttydev, O_RDWR)) == -1)
fatal("Cannot open %s: %s", ttydev, strerror(errno));
if (dup2(j, 0) == -1)
fatal("dup2 failed: %s", strerror(errno));
close(j);
#else
new_argv[i++] = ttydev;
new_argv[i++] = str_38400;
#endif
for (j = 0; j < argc; j++)
new_argv[i++] = argv[j];
new_argv[i] = NULL;
execvp(new_argv[0], new_argv);
}

416
pptp_callmgr.c Normal file
View File

@ -0,0 +1,416 @@
/* pptp_callmgr.c ... Call manager for PPTP connections.
* Handles TCP port 1723 protocol.
* C. Scott Ananian <cananian@alumni.princeton.edu>
*
* $Id: pptp_callmgr.c,v 1.27 2011/12/19 07:18:09 quozl Exp $
*/
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#if defined (__SVR4) && defined (__sun)
#include <strings.h>
#endif
#include <assert.h>
#include <setjmp.h>
#include <stdio.h>
#include <errno.h>
#include "pptp_callmgr.h"
#include "pptp_ctrl.h"
#include "pptp_msg.h"
#include "dirutil.h"
#include "vector.h"
#include "util.h"
#include "routing.h"
extern struct in_addr localbind; /* from pptp.c */
extern int rtmark;
extern int nohostroute;
int open_inetsock(struct in_addr inetaddr);
int open_unixsock(struct in_addr inetaddr);
void close_inetsock(int fd, struct in_addr inetaddr);
void close_unixsock(int fd, struct in_addr inetaddr);
sigjmp_buf callmgr_env;
void callmgr_sighandler(int sig __attribute__ ((unused))) {
/* TODO: according to signal(2), siglongjmp() is unsafe used here */
siglongjmp (callmgr_env, 1);
}
void callmgr_do_nothing(int sig __attribute__ ((unused))) {
/* do nothing signal handler */
}
struct local_callinfo {
int unix_sock;
pid_t pid[2];
};
struct local_conninfo {
VECTOR * call_list;
fd_set * call_set;
};
/* Call callback */
void call_callback(PPTP_CONN *conn, PPTP_CALL *call, enum call_state state)
{
struct local_callinfo *lci;
struct local_conninfo *conninfo;
u_int16_t call_id[2];
switch(state) {
case CALL_OPEN_DONE:
/* okey dokey. This means that the call_id and peer_call_id are
* now valid, so lets send them on to our friends who requested
* this call. */
lci = pptp_call_closure_get(conn, call); assert(lci != NULL);
pptp_call_get_ids(conn, call, &call_id[0], &call_id[1]);
write(lci->unix_sock, &call_id, sizeof(call_id));
/* Our duty to the fatherland is now complete. */
break;
case CALL_OPEN_FAIL:
case CALL_CLOSE_RQST:
case CALL_CLOSE_DONE:
/* don't need to do anything here, except make sure tables
* are sync'ed */
log("Closing connection (call state)");
conninfo = pptp_conn_closure_get(conn);
lci = pptp_call_closure_get(conn, call);
assert(lci != NULL && conninfo != NULL);
if (vector_contains(conninfo->call_list, lci->unix_sock)) {
vector_remove(conninfo->call_list, lci->unix_sock);
close(lci->unix_sock);
FD_CLR(lci->unix_sock, conninfo->call_set);
if(lci->pid[0] > 1) kill(lci->pid[0], SIGTERM);
if(lci->pid[1] > 1) kill(lci->pid[1], SIGTERM);
}
break;
default:
log("Unhandled call callback state [%d].", (int) state);
break;
}
}
/******************************************************************************
* NOTE ABOUT 'VOLATILE':
* several variables here get a volatile qualifier to silence warnings
* from older (before 3.0) gccs. if the longjmp stuff is removed,
* the volatile qualifiers should be removed as well.
*****************************************************************************/
/*** Call Manager *************************************************************/
int callmgr_main(int argc, char **argv, char **envp __attribute__ ((unused)))
{
struct in_addr inetaddr;
int inet_sock, unix_sock;
fd_set call_set;
PPTP_CONN * conn;
VECTOR * call_list;
int max_fd = 0;
volatile int first = 1;
int retval;
int i;
char * volatile phonenr;
/* Step 0: Check arguments */
if (argc < 2)
fatal("Usage: %s ip.add.ress.here [--phone <phone number>]", argv[0]);
phonenr = argc == 3 ? argv[2] : NULL;
if (inet_aton(argv[1], &inetaddr) == 0)
fatal("Invalid IP address: %s", argv[1]);
if (!nohostroute) {
routing_init(inet_ntoa(inetaddr));
routing_start();
}
/* Step 1: Open sockets. */
if ((inet_sock = open_inetsock(inetaddr)) < 0)
fatal("Could not open control connection to %s", argv[1]);
if ((unix_sock = open_unixsock(inetaddr)) < 0)
fatal("Could not open unix socket for %s", argv[1]);
/* Step 1b: FORK and return status to calling process. */
switch (fork()) {
case 0: /* child. stick around. */
break;
case -1: /* failure. Fatal. */
fatal("Could not fork.");
default: /* Parent. Return status to caller. */
exit(0);
}
/* re-open stderr as /dev/null to release it */
file2fd("/dev/null", "wb", STDERR_FILENO);
/* Step 1c: Clean up unix socket on TERM */
if (sigsetjmp(callmgr_env, 1) != 0)
goto cleanup;
signal(SIGINT, callmgr_sighandler);
signal(SIGTERM, callmgr_sighandler);
signal(SIGPIPE, callmgr_do_nothing);
signal(SIGUSR1, callmgr_do_nothing); /* signal state change
wake up accept */
/* Step 2: Open control connection and register callback */
if ((conn = pptp_conn_open(inet_sock, 1, NULL/* callback */)) == NULL) {
close(unix_sock); close(inet_sock); fatal("Could not open connection.");
}
FD_ZERO(&call_set);
call_list = vector_create();
{
struct local_conninfo *conninfo = malloc(sizeof(*conninfo));
if (conninfo == NULL) {
close(unix_sock); close(inet_sock); fatal("No memory.");
}
conninfo->call_list = call_list;
conninfo->call_set = &call_set;
pptp_conn_closure_put(conn, conninfo);
}
if (sigsetjmp(callmgr_env, 1) != 0) goto shutdown;
/* Step 3: Get FD_SETs */
max_fd = unix_sock;
do {
int rc;
fd_set read_set = call_set, write_set;
if (pptp_conn_is_dead(conn)) break;
FD_ZERO (&write_set);
if (pptp_conn_established(conn)) {
FD_SET (unix_sock, &read_set);
if (unix_sock > max_fd) max_fd = unix_sock;
}
pptp_fd_set(conn, &read_set, &write_set, &max_fd);
for (; max_fd > 0 ; max_fd--) {
if (FD_ISSET (max_fd, &read_set) ||
FD_ISSET (max_fd, &write_set))
break;
}
/* Step 4: Wait on INET or UNIX event */
if ((rc = select(max_fd + 1, &read_set, &write_set, NULL, NULL)) <0) {
if (errno == EBADF) break;
/* a signal or somesuch. */
continue;
}
/* Step 5a: Handle INET events */
rc = pptp_dispatch(conn, &read_set, &write_set);
if (rc < 0)
break;
/* Step 5b: Handle new connection to UNIX socket */
if (FD_ISSET(unix_sock, &read_set)) {
/* New call! */
union {
struct sockaddr a;
struct sockaddr_un u;
} from;
socklen_t len = sizeof(from.u);
PPTP_CALL * call;
struct local_callinfo *lci;
int s;
/* Accept the socket */
FD_CLR (unix_sock, &read_set);
if ((s = accept(unix_sock, &from.a, &len)) < 0) {
warn("Socket not accepted: %s", strerror(errno));
goto skip_accept;
}
/* Allocate memory for local call information structure. */
if ((lci = malloc(sizeof(*lci))) == NULL) {
warn("Out of memory."); close(s); goto skip_accept;
}
lci->unix_sock = s;
/* Give the initiator time to write the PIDs while we open
* the call */
call = pptp_call_open(conn, call_callback, phonenr);
/* Read and store the associated pids */
read(s, &lci->pid[0], sizeof(lci->pid[0]));
read(s, &lci->pid[1], sizeof(lci->pid[1]));
/* associate the local information with the call */
pptp_call_closure_put(conn, call, (void *) lci);
/* The rest is done on callback. */
/* Keep alive; wait for close */
retval = vector_insert(call_list, s, call); assert(retval);
if (s > max_fd) max_fd = s;
FD_SET(s, &call_set);
first = 0;
}
skip_accept: /* Step 5c: Handle socket close */
for (i = 0; i < max_fd + 1; i++)
if (FD_ISSET(i, &read_set)) {
/* close it */
PPTP_CALL * call;
retval = vector_search(call_list, i, &call);
if (retval) {
struct local_callinfo *lci =
pptp_call_closure_get(conn, call);
log("Closing connection (unhandled)");
if(lci->pid[0] > 1) kill(lci->pid[0], SIGTERM);
if(lci->pid[1] > 1) kill(lci->pid[1], SIGTERM);
free(lci);
/* soft shutdown. Callback will do hard shutdown later */
pptp_call_close(conn, call);
vector_remove(call_list, i);
}
FD_CLR(i, &call_set);
close(i);
}
} while (vector_size(call_list) > 0 || first);
shutdown:
{
int rc;
fd_set read_set, write_set;
struct timeval tv;
signal(SIGINT, callmgr_do_nothing);
signal(SIGTERM, callmgr_do_nothing);
/* warn("Shutdown"); */
/* kill all open calls */
for (i = 0; i < vector_size(call_list); i++) {
PPTP_CALL *call = vector_get_Nth(call_list, i);
struct local_callinfo *lci = pptp_call_closure_get(conn, call);
log("Closing connection (shutdown)");
pptp_call_close(conn, call);
if(lci->pid[0] > 1) kill(lci->pid[0], SIGTERM);
if(lci->pid[1] > 1) kill(lci->pid[1], SIGTERM);
}
/* attempt to dispatch these messages */
FD_ZERO(&read_set);
FD_ZERO(&write_set);
pptp_fd_set(conn, &read_set, &write_set, &max_fd);
tv.tv_sec = 0;
tv.tv_usec = 0;
select(max_fd + 1, &read_set, &write_set, NULL, &tv);
rc = pptp_dispatch(conn, &read_set, &write_set);
if (rc > 0) {
/* wait for a respond, a timeout because there might not be one */
FD_ZERO(&read_set);
FD_ZERO(&write_set);
pptp_fd_set(conn, &read_set, &write_set, &max_fd);
tv.tv_sec = 2;
tv.tv_usec = 0;
select(max_fd + 1, &read_set, &write_set, NULL, &tv);
rc = pptp_dispatch(conn, &read_set, &write_set);
if (rc > 0) {
if (i > 0) sleep(2);
/* no more open calls. Close the connection. */
pptp_conn_close(conn, PPTP_STOP_LOCAL_SHUTDOWN);
/* wait for a respond, a timeout because there might not be one */
FD_ZERO(&read_set);
FD_ZERO(&write_set);
pptp_fd_set(conn, &read_set, &write_set, &max_fd);
tv.tv_sec = 2;
tv.tv_usec = 0;
select(max_fd + 1, &read_set, &write_set, NULL, &tv);
pptp_dispatch(conn, &read_set, &write_set);
if (rc > 0) sleep(2);
}
}
/* with extreme prejudice */
pptp_conn_destroy(conn);
pptp_conn_free(conn);
vector_destroy(call_list);
}
cleanup:
signal(SIGINT, callmgr_do_nothing);
signal(SIGTERM, callmgr_do_nothing);
close_inetsock(inet_sock, inetaddr);
close_unixsock(unix_sock, inetaddr);
return 0;
}
/*** open_inetsock ************************************************************/
int open_inetsock(struct in_addr inetaddr)
{
union {
struct sockaddr a;
struct sockaddr_in i;
} dest, src;
int s;
dest.i.sin_family = AF_INET;
dest.i.sin_port = htons(PPTP_PORT);
dest.i.sin_addr = inetaddr;
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
warn("socket: %s", strerror(errno));
return s;
}
#ifdef SO_MARK
if (rtmark) {
if (setsockopt(s, SOL_SOCKET, SO_MARK, &rtmark, sizeof(rtmark))) {
warn("setsockopt(SO_MARK): %s", strerror(errno));
close(s); return -1;
}
}
#endif
if (localbind.s_addr != INADDR_NONE) {
bzero(&src, sizeof(src));
src.i.sin_family = AF_INET;
src.i.sin_addr = localbind;
if (bind(s, &src.a, sizeof(src.i)) != 0) {
warn("bind: %s", strerror(errno));
close(s); return -1;
}
}
if (connect(s, &dest.a, sizeof(dest.i)) < 0) {
warn("connect: %s", strerror(errno));
close(s); return -1;
}
return s;
}
/*** open_unixsock ************************************************************/
int open_unixsock(struct in_addr inetaddr)
{
union {
struct sockaddr a;
struct sockaddr_un u;
} where;
struct stat st;
char *dir;
int s;
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
warn("socket: %s", strerror(errno));
return s;
}
callmgr_name_unixsock( &where.u, inetaddr, localbind);
if (stat(where.u.sun_path, &st) >= 0) {
warn("Call manager for %s is already running.", inet_ntoa(inetaddr));
close(s); return -1;
}
/* Make sure path is valid. */
dir = dirname(where.u.sun_path);
if (!make_valid_path(dir, 0770))
fatal("Could not make path to %s: %s", where.u.sun_path, strerror(errno));
free(dir);
if (bind(s, &where.a, sizeof(where.u)) < 0) {
warn("bind: %s", strerror(errno));
close(s); return -1;
}
chmod(where.u.sun_path, 0777);
listen(s, 127);
return s;
}
/*** close_inetsock ***********************************************************/
void close_inetsock(int fd, struct in_addr inetaddr __attribute__ ((unused)))
{
close(fd);
}
/*** close_unixsock ***********************************************************/
void close_unixsock(int fd, struct in_addr inetaddr)
{
struct sockaddr_un where;
close(fd);
callmgr_name_unixsock(&where, inetaddr, localbind);
unlink(where.sun_path);
}
/*** make a unix socket address ***********************************************/
void callmgr_name_unixsock(struct sockaddr_un *where,
struct in_addr inetaddr,
struct in_addr localbind)
{
char localaddr[16];
where->sun_family = AF_UNIX;
strcpy(localaddr, inet_ntoa(localbind));
snprintf(where->sun_path, sizeof(where->sun_path),
PPTP_SOCKET_PREFIX "%s:%s", localaddr, inet_ntoa(inetaddr));
}

13
pptp_callmgr.h Normal file
View File

@ -0,0 +1,13 @@
/* pptp_callmgr.h ... Call manager for PPTP connections.
* Handles TCP port 1723 protocol.
* C. Scott Ananian <cananian@alumni.princeton.edu>
*
* $Id: pptp_callmgr.h,v 1.3 2003/02/17 00:22:17 quozl Exp $
*/
#define PPTP_SOCKET_PREFIX "/var/run/pptp/"
int callmgr_main(int argc, char**argv, char**envp);
void callmgr_name_unixsock(struct sockaddr_un *where,
struct in_addr inetaddr,
struct in_addr localbind);

93
pptp_compat.c Normal file
View File

@ -0,0 +1,93 @@
/* pptp_compat.c ... Compatibility functions
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#if defined (__SVR4) && defined (__sun) /* Solaris */
#include <stropts.h>
#endif
#include <strings.h>
#include "pptp_compat.h"
#include <stdio.h>
#include "util.h"
#if defined (__SVR4) && defined (__sun) /* Solaris */
/*
* daemon implementation from uClibc
*/
int daemon(int nochdir, int noclose)
{
int fd;
switch (fork()) {
case -1:
return (-1);
case 0:
break;
default:
_exit(0);
}
if (setsid() == -1)
return (-1);
if (!nochdir)
chdir("/");
if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
if (fd > 2)
close (fd);
}
return (0);
}
/*
* openpty implementation based on pts(7D) example
*/
int openpty(int *amaster, int *aslave, char *name, struct termios *termp, struct winsize * winp) {
int fdm,fds;
char * slavename;
/* open master */
if ( (fdm = open("/dev/ptmx", O_RDWR)) == -1 )
return -1;
/* grant access to the slave pseudo-terminal device */
if ( grantpt(fdm) == -1 )
return -1;
/* unlock a pseudo-terminal master/slave pair */
if ( unlockpt(fdm) == -1 )
return -1;
/* get name of the slave pseudo-terminal device */
if ( (slavename = ptsname(fdm)) == NULL )
return -1;
if ( (fds = open(slavename, O_RDWR)) == -1 ) {
free(slavename);
return -1;
}
ioctl(fds, I_PUSH, "ptem"); /* push ptem */
ioctl(fds, I_PUSH, "ldterm"); /* push ldterm*/
if ( name != NULL )
strcpy(name,slavename);
*amaster = fdm;
*aslave = fds;
free(slavename);
return 0;
}
#endif /* Solaris */

18
pptp_compat.h Normal file
View File

@ -0,0 +1,18 @@
/* pptp_compat.h ... Compatibility functions
*
*/
#if defined (__SVR4) && defined (__sun) /* Solaris */
#include <sys/termios.h>
#define u_int8_t uint8_t
#define u_int16_t uint16_t
#define u_int32_t uint32_t
#ifndef INADDR_NONE
#define INADDR_NONE 0xffffffffU
#endif
int daemon(int nochdir, int noclose);
int openpty(int *amaster, int *aslave, char *name, struct termios *termp, struct winsize * winp);
#endif /* Solaris */

1137
pptp_ctrl.c Normal file

File diff suppressed because it is too large Load Diff

60
pptp_ctrl.h Normal file
View File

@ -0,0 +1,60 @@
/* pptp_ctrl.h ... handle PPTP control connection.
* C. Scott Ananian <cananian@alumni.princeton.edu>
*
* $Id: pptp_ctrl.h,v 1.7 2010/06/15 05:04:32 quozl Exp $
*/
#ifndef INC_PPTP_CTRL_H
#define INC_PPTP_CTRL_H
#include <sys/types.h>
#include "pptp_compat.h"
typedef struct PPTP_CONN PPTP_CONN;
typedef struct PPTP_CALL PPTP_CALL;
enum call_state { CALL_OPEN_RQST, CALL_OPEN_DONE, CALL_OPEN_FAIL,
CALL_CLOSE_RQST, CALL_CLOSE_DONE };
enum conn_state { CONN_OPEN_RQST, CONN_OPEN_DONE, CONN_OPEN_FAIL,
CONN_CLOSE_RQST, CONN_CLOSE_DONE };
typedef void (*pptp_call_cb)(PPTP_CONN*, PPTP_CALL*, enum call_state);
typedef void (*pptp_conn_cb)(PPTP_CONN*, enum conn_state);
/* if 'isclient' is true, then will send 'conn open' packet to other host.
* not necessary if this is being opened by a server process after
* receiving a conn_open packet from client.
*/
PPTP_CONN * pptp_conn_open(int inet_sock, int isclient,
pptp_conn_cb callback);
PPTP_CALL * pptp_call_open(PPTP_CONN * conn,
pptp_call_cb callback, char *phonenr);
int pptp_conn_established(PPTP_CONN * conn);
/* soft close. Will callback on completion. */
void pptp_call_close(PPTP_CONN * conn, PPTP_CALL * call);
/* hard close. */
void pptp_call_destroy(PPTP_CONN *conn, PPTP_CALL *call);
int pptp_conn_is_dead(PPTP_CONN * conn);
void pptp_conn_free(PPTP_CONN * conn);
/* soft close. Will callback on completion. */
void pptp_conn_close(PPTP_CONN * conn, u_int8_t close_reason);
/* hard close */
void pptp_conn_destroy(PPTP_CONN * conn);
/* Add file descriptors used by pptp to fd_set. */
void pptp_fd_set(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set, int *max_fd);
/* handle any pptp file descriptors set in fd_set, and clear them */
int pptp_dispatch(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set);
/* Get info about connection, call */
void pptp_call_get_ids(PPTP_CONN * conn, PPTP_CALL * call,
u_int16_t * call_id, u_int16_t * peer_call_id);
/* Arbitrary user data about this call/connection.
* It is the caller's responsibility to free this data before calling
* pptp_call|conn_close()
*/
void * pptp_conn_closure_get(PPTP_CONN * conn);
void pptp_conn_closure_put(PPTP_CONN * conn, void *cl);
void * pptp_call_closure_get(PPTP_CONN * conn, PPTP_CALL * call);
void pptp_call_closure_put(PPTP_CONN * conn, PPTP_CALL * call, void *cl);
#endif /* INC_PPTP_CTRL_H */

559
pptp_gre.c Normal file
View File

@ -0,0 +1,559 @@
/* pptp_gre.c -- encapsulate PPP in PPTP-GRE.
* Handle the IP Protocol 47 portion of PPTP.
* C. Scott Ananian <cananian@alumni.princeton.edu>
*
* $Id: pptp_gre.c,v 1.49 2011/12/19 07:18:09 quozl Exp $
*/
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#if defined (__SVR4) && defined (__sun)
#include <strings.h>
#endif
#include <errno.h>
#include <fcntl.h>
#include "ppp_fcs.h"
#include "pptp_msg.h"
#include "pptp_gre.h"
#include "util.h"
#include "pqueue.h"
#include "test-redirections.h"
/* globals from pptp.c */
extern struct in_addr localbind;
extern int rtmark;
#define PACKET_MAX 8196
/* test for a 32 bit counter overflow */
#define WRAPPED( curseq, lastseq) \
((((curseq) & 0xffffff00) == 0) && \
(((lastseq) & 0xffffff00 ) == 0xffffff00))
static u_int32_t ack_sent, ack_recv;
static u_int32_t seq_sent, seq_recv;
static u_int16_t pptp_gre_call_id, pptp_gre_peer_call_id;
gre_stats_t stats;
typedef int (*callback_t)(int cl, void *pack, unsigned int len);
/* decaps_hdlc gets all the packets possible with ONE blocking read */
/* returns <0 if read() call fails */
int decaps_hdlc(int fd, callback_t callback, int cl);
int encaps_hdlc(int fd, void *pack, unsigned int len);
int decaps_gre (int fd, callback_t callback, int cl);
int encaps_gre (int fd, void *pack, unsigned int len);
int dequeue_gre(callback_t callback, int cl);
/* test redirection function pointers */
struct test_redirections *my;
unsigned char dest[2 * PACKET_MAX + 2]; /* largest expansion possible */
#undef PRINT_PACKETS
#ifdef PRINT_PACKETS
#include <stdio.h>
void print_packet(int fd, void *pack, unsigned int len)
{
unsigned char *b = (unsigned char *)pack;
unsigned int i,j;
static FILE *out = NULL;
if (out == NULL) out = fdopen(fd, "w");
fprintf(out,"-- begin packet (%u) --\n", len);
for (i = 0; i < len; i += 16) {
for (j = 0; j < 8; j++)
if (i + 2 * j + 1 < len)
fprintf(out, "%02x%02x ",
(unsigned int) b[i + 2 * j],
(unsigned int) b[i + 2 * j + 1]);
else if (i + 2 * j < len)
fprintf(out, "%02x ", (unsigned int) b[i + 2 * j]);
fprintf(out, "\n");
}
fprintf(out, "-- end packet --\n");
fflush(out);
}
#endif /* PRINT_PACKETS */
/*** time_now_usecs ***********************************************************/
uint64_t time_now_usecs(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (tv.tv_sec * 1000000) + tv.tv_usec;
}
/*** Open IP protocol socket **************************************************/
int pptp_gre_bind(struct in_addr inetaddr)
{
union {
struct sockaddr a;
struct sockaddr_in i;
} loc_addr, src_addr;
int s = socket(AF_INET, SOCK_RAW, PPTP_PROTO);
if (s < 0) { warn("socket: %s", strerror(errno)); return -1; }
#ifdef SO_MARK
if (rtmark) {
if (setsockopt(s, SOL_SOCKET, SO_MARK, &rtmark, sizeof(rtmark))) {
warn("setsockopt(SO_MARK): %s", strerror(errno));
close(s); return -1;
}
}
#endif
if (localbind.s_addr != INADDR_NONE) {
bzero(&loc_addr, sizeof(loc_addr));
loc_addr.i.sin_family = AF_INET;
loc_addr.i.sin_addr = localbind;
if (bind(s, &loc_addr.a, sizeof(loc_addr.i)) != 0) {
warn("bind: %s", strerror(errno)); close(s); return -1;
}
}
src_addr.i.sin_family = AF_INET;
src_addr.i.sin_addr = inetaddr;
src_addr.i.sin_port = 0;
if (connect(s, &src_addr.a, sizeof(src_addr.i)) < 0) {
warn("connect: %s", strerror(errno)); close(s); return -1;
}
my = test_redirections();
return s;
}
/*** pptp_gre_copy ************************************************************/
void pptp_gre_copy(u_int16_t call_id, u_int16_t peer_call_id,
int pty_fd, int gre_fd)
{
int max_fd;
pptp_gre_call_id = call_id;
pptp_gre_peer_call_id = peer_call_id;
/* Pseudo-terminal already open. */
ack_sent = ack_recv = seq_sent = seq_recv = 0;
/* weird select semantics */
max_fd = gre_fd;
if (pty_fd > max_fd) max_fd = pty_fd;
/* Dispatch loop */
for (;;) { /* until error happens on gre_fd or pty_fd */
struct timeval tv = {0, 0};
struct timeval *tvp;
fd_set rfds;
int retval;
pqueue_t *head;
int block_usecs = -1; /* wait forever */
/* watch terminal and socket for input */
FD_ZERO(&rfds);
FD_SET(gre_fd, &rfds);
FD_SET(pty_fd, &rfds);
/*
* if there are multiple pending ACKs, then do a minimal timeout;
* else if there is a single pending ACK then timeout after 0,5 seconds;
* else block until data is available.
*/
if (ack_sent != seq_recv) {
if (ack_sent + 1 == seq_recv) /* u_int wrap-around safe */
block_usecs = 500000;
else
/* don't use zero, this will force a resceduling */
/* when calling select(), giving pppd a chance to */
/* run. */
block_usecs = 1;
}
/* otherwise block_usecs == -1, which means wait forever */
/*
* If there is a packet in the queue, then don't wait longer than
* the time remaining until it expires.
*/
head = pqueue_head();
if (head != NULL) {
int expiry_time = pqueue_expiry_time(head);
if (block_usecs == -1 || expiry_time < block_usecs)
block_usecs = expiry_time;
}
if (block_usecs == -1) {
tvp = NULL;
} else {
tvp = &tv;
tv.tv_usec = block_usecs;
tv.tv_sec = tv.tv_usec / 1000000;
tv.tv_usec %= 1000000;
}
retval = select(max_fd + 1, &rfds, NULL, NULL, tvp);
if (retval > 0 && FD_ISSET(pty_fd, &rfds)) {
if (decaps_hdlc(pty_fd, encaps_gre, gre_fd) < 0)
break;
} else if (retval == 0 && ack_sent != seq_recv) {
/* if outstanding ack */
/* send ack with no payload */
encaps_gre(gre_fd, NULL, 0);
}
if (retval > 0 && FD_ISSET(gre_fd, &rfds)) {
if (decaps_gre (gre_fd, encaps_hdlc, pty_fd) < 0)
break;
}
if (dequeue_gre (encaps_hdlc, pty_fd) < 0)
break;
}
/* Close up when done. */
close(gre_fd);
close(pty_fd);
}
#define HDLC_FLAG 0x7E
#define HDLC_ESCAPE 0x7D
#define HDLC_TRANSPARENCY 0x20
/* ONE blocking read per call; dispatches all packets possible */
/* returns 0 on success, or <0 on read failure */
int decaps_hdlc(int fd, int (*cb)(int cl, void *pack, unsigned int len), int cl)
{
unsigned char buffer[PACKET_MAX];
ssize_t start = 0, end;
int status;
static unsigned int len = 0, escape = 0;
static unsigned char copy[PACKET_MAX];
static int checkedsync = 0;
/* start is start of packet. end is end of buffer data */
/* this is the only blocking read we will allow */
if ((end = read (fd, buffer, sizeof(buffer))) <= 0) {
int saved_errno = errno;
warn("short read (%zd): %s", end, strerror(saved_errno));
switch (saved_errno) {
case EMSGSIZE: {
socklen_t optval, optlen = sizeof(optval);
warn("transmitted GRE packet triggered an ICMP destination unreachable, fragmentation needed, or exceeds the MTU of the network interface");
#define IP_MTU 14
if(getsockopt(fd, IPPROTO_IP, IP_MTU, &optval, &optlen) < 0)
warn("getsockopt: %s", strerror(errno));
warn("getsockopt: IP_MTU: %d\n", optval);
return 0;
}
case EIO:
warn("pppd may have shutdown, see pppd log");
break;
}
return -1;
}
/* warn if the sync options of ppp and pptp don't match */
if( !checkedsync) {
checkedsync = 1;
if( buffer[0] == HDLC_FLAG){
if( syncppp )
warn( "pptp --sync option is active, "
"yet the ppp mode is asynchronous!\n");
}
else if( !syncppp )
warn( "The ppp mode is synchronous, "
"yet no pptp --sync option is specified!\n");
}
/* in synchronous mode there are no hdlc control characters nor checksum
* bytes. Find end of packet with the length information in the PPP packet
*/
if ( syncppp ){
while ( start + 8 < end) {
len = ntoh16(*(short int *)(buffer + start + 6)) + 4;
/* note: the buffer may contain an incomplete packet at the end
* this packet will be read again at the next read() */
if ( start + len <= end)
if ((status = cb (cl, buffer + start, len)) < 0)
return status; /* error-check */
start += len;
}
return 0;
}
/* asynchronous mode */
while (start < end) {
/* Copy to 'copy' and un-escape as we go. */
while (buffer[start] != HDLC_FLAG) {
if ((escape == 0) && buffer[start] == HDLC_ESCAPE) {
escape = HDLC_TRANSPARENCY;
} else {
if (len < PACKET_MAX)
copy [len++] = buffer[start] ^ escape;
escape = 0;
}
start++;
if (start >= end)
return 0; /* No more data, but the frame is not complete yet. */
}
/* found flag. skip past it */
start++;
/* check for over-short packets and silently discard, as per RFC1662 */
if ((len < 4) || (escape != 0)) {
len = 0; escape = 0;
continue;
}
/* check, then remove the 16-bit FCS checksum field */
if (pppfcs16 (PPPINITFCS16, copy, len) != PPPGOODFCS16)
warn("Bad Frame Check Sequence during PPP to GRE decapsulation");
len -= sizeof(u_int16_t);
/* so now we have a packet of length 'len' in 'copy' */
if ((status = cb (cl, copy, len)) < 0)
return status; /* error-check */
/* Great! Let's do more! */
len = 0; escape = 0;
}
return 0;
/* No more data to process. */
}
/*** Make stripped packet into HDLC packet ************************************/
int encaps_hdlc(int fd, void *pack, unsigned int len)
{
unsigned char *source = (unsigned char *)pack;
unsigned int pos = 0, i;
u_int16_t fcs;
/* in synchronous mode there is little to do */
if ( syncppp )
return write(fd, source, len);
/* asynchronous mode */
/* Compute the FCS */
fcs = pppfcs16(PPPINITFCS16, source, len) ^ 0xFFFF;
/* start character */
dest[pos++] = HDLC_FLAG;
/* escape the payload */
for (i = 0; i < len + 2; i++) {
/* wacked out assignment to add FCS to end of source buffer */
unsigned char c =
(i < len)?source[i]:(i == len)?(fcs & 0xFF):((fcs >> 8) & 0xFF);
if (pos >= sizeof(dest)) break; /* truncate on overflow */
if ( (c < 0x20) || (c == HDLC_FLAG) || (c == HDLC_ESCAPE) ) {
dest[pos++] = HDLC_ESCAPE;
if (pos < sizeof(dest))
dest[pos++] = c ^ 0x20;
} else
dest[pos++] = c;
}
/* tack on the end-flag */
if (pos < sizeof(dest))
dest[pos++] = HDLC_FLAG;
/* now write this packet */
return write(fd, dest, pos);
}
/*** decaps_gre ***************************************************************/
int decaps_gre (int fd, callback_t callback, int cl)
{
unsigned char buffer[PACKET_MAX + 64 /*ip header*/];
struct pptp_gre_header *header;
int status, ip_len = 0;
static int first = 1;
unsigned int headersize;
unsigned int payload_len;
u_int32_t seq;
if ((status = read (fd, buffer, sizeof(buffer))) <= 0) {
warn("short read (%d): %s", status, strerror(errno));
stats.rx_errors++;
return -1;
}
/* strip off IP header, if present */
if ((buffer[0] & 0xF0) == 0x40)
ip_len = (buffer[0] & 0xF) * 4;
header = (struct pptp_gre_header *)(buffer + ip_len);
/* verify packet (else discard) */
if ( /* version should be 1 */
((ntoh8(header->ver) & 0x7F) != PPTP_GRE_VER) ||
/* PPTP-GRE protocol for PPTP */
(ntoh16(header->protocol) != PPTP_GRE_PROTO)||
/* flag C should be clear */
PPTP_GRE_IS_C(ntoh8(header->flags)) ||
/* flag R should be clear */
PPTP_GRE_IS_R(ntoh8(header->flags)) ||
/* flag K should be set */
(!PPTP_GRE_IS_K(ntoh8(header->flags))) ||
/* routing and recursion ctrl = 0 */
((ntoh8(header->flags)&0xF) != 0)) {
/* if invalid, discard this packet */
warn("Discarding GRE: %X %X %X %X %X %X",
ntoh8(header->ver)&0x7F, ntoh16(header->protocol),
PPTP_GRE_IS_C(ntoh8(header->flags)),
PPTP_GRE_IS_R(ntoh8(header->flags)),
PPTP_GRE_IS_K(ntoh8(header->flags)),
ntoh8(header->flags) & 0xF);
stats.rx_invalid++;
return 0;
}
/* silently discard packets not for this call */
if (ntoh16(header->call_id) != pptp_gre_call_id) return 0;
/* test if acknowledgement present */
if (PPTP_GRE_IS_A(ntoh8(header->ver))) {
u_int32_t ack = (PPTP_GRE_IS_S(ntoh8(header->flags)))?
header->ack:header->seq; /* ack in different place if S = 0 */
ack = ntoh32( ack);
if (ack > ack_recv) ack_recv = ack;
/* also handle sequence number wrap-around */
if (WRAPPED(ack,ack_recv)) ack_recv = ack;
if (ack_recv == stats.pt.seq) {
int rtt = time_now_usecs() - stats.pt.time;
stats.rtt = (stats.rtt + rtt) / 2;
}
}
/* test if payload present */
if (!PPTP_GRE_IS_S(ntoh8(header->flags)))
return 0; /* ack, but no payload */
headersize = sizeof(*header);
payload_len = ntoh16(header->payload_len);
seq = ntoh32(header->seq);
/* no ack present? */
if (!PPTP_GRE_IS_A(ntoh8(header->ver))) headersize -= sizeof(header->ack);
/* check for incomplete packet (length smaller than expected) */
if (status - headersize < payload_len) {
warn("discarding truncated packet (expected %d, got %d bytes)",
payload_len, status - headersize);
stats.rx_truncated++;
return 0;
}
/* check for expected sequence number */
if ( first || (seq == seq_recv + 1)) { /* wrap-around safe */
if ( log_level >= 2 )
log("accepting packet %d", seq);
stats.rx_accepted++;
first = 0;
seq_recv = seq;
return callback(cl, buffer + ip_len + headersize, payload_len);
/* out of order, check if the number is too low and discard the packet.
* (handle sequence number wrap-around, and try to do it right) */
} else if ( seq < seq_recv + 1 || WRAPPED(seq_recv, seq) ) {
if ( log_level >= 1 )
log("discarding duplicate or old packet %d (expecting %d)",
seq, seq_recv + 1);
stats.rx_underwin++;
/* sequence number too high, is it reasonably close? */
} else if ( (seq < seq_recv + missing_window ||
WRAPPED(seq, seq_recv + missing_window)) ||
(missing_window == -1) ) {
stats.rx_buffered++;
if ( log_level >= 1 )
log("%s packet %d (expecting %d, lost or reordered)",
disable_buffer ? "accepting" : "buffering",
seq, seq_recv+1);
if ( disable_buffer ) {
seq_recv = seq;
stats.rx_lost += seq - seq_recv - 1;
return callback(cl, buffer + ip_len + headersize, payload_len);
} else {
pqueue_add(seq, buffer + ip_len + headersize, payload_len);
}
/* no, packet must be discarded */
} else {
if ( log_level >= 1 )
warn("discarding bogus packet %d (expecting %d)",
seq, seq_recv + 1);
stats.rx_overwin++;
}
return 0;
}
/*** dequeue_gre **************************************************************/
int dequeue_gre (callback_t callback, int cl)
{
pqueue_t *head;
int status;
/* process packets in the queue that either are expected or have
* timed out. */
head = pqueue_head();
while ( head != NULL &&
( (head->seq == seq_recv + 1) || /* wrap-around safe */
(pqueue_expiry_time(head) <= 0)
)
) {
/* if it is timed out... */
if (head->seq != seq_recv + 1 ) { /* wrap-around safe */
stats.rx_lost += head->seq - seq_recv - 1;
if (log_level >= 2)
log("timeout waiting for %d packets", head->seq - seq_recv - 1);
}
if (log_level >= 2)
log("accepting %d from queue", head->seq);
seq_recv = head->seq;
status = callback(cl, head->packet, head->packlen);
pqueue_del(head);
if (status < 0)
return status;
head = pqueue_head();
}
return 0;
}
/*** encaps_gre ***************************************************************/
int encaps_gre (int fd, void *pack, unsigned int len)
{
union {
struct pptp_gre_header header;
unsigned char buffer[PACKET_MAX + sizeof(struct pptp_gre_header)];
} u;
static u_int32_t seq = 1; /* first sequence number sent must be 1 */
unsigned int header_len;
int rc;
/* package this up in a GRE shell. */
u.header.flags = hton8 (PPTP_GRE_FLAG_K);
u.header.ver = hton8 (PPTP_GRE_VER);
u.header.protocol = hton16(PPTP_GRE_PROTO);
u.header.payload_len = hton16(len);
u.header.call_id = hton16(pptp_gre_peer_call_id);
/* special case ACK with no payload */
if (pack == NULL) {
if (ack_sent != seq_recv) {
u.header.ver |= hton8(PPTP_GRE_FLAG_A);
u.header.payload_len = hton16(0);
/* ack is in odd place because S == 0 */
u.header.seq = hton32(seq_recv);
ack_sent = seq_recv;
rc = (*my->write)(fd, &u.header,
sizeof(u.header) - sizeof(u.header.seq));
if (rc < 0) {
if (errno == ENOBUFS)
rc = 0; /* Simply ignore it */
stats.tx_failed++;
} else if ((size_t)rc < sizeof(u.header) - sizeof(u.header.seq)) {
stats.tx_short++;
} else {
stats.tx_acks++;
}
return rc;
} else return 0; /* we don't need to send ACK */
} /* explicit brace to avoid ambiguous `else' warning */
/* send packet with payload */
u.header.flags |= hton8(PPTP_GRE_FLAG_S);
u.header.seq = hton32(seq);
if (ack_sent != seq_recv) { /* send ack with this message */
u.header.ver |= hton8(PPTP_GRE_FLAG_A);
u.header.ack = hton32(seq_recv);
ack_sent = seq_recv;
header_len = sizeof(u.header);
} else { /* don't send ack */
header_len = sizeof(u.header) - sizeof(u.header.ack);
}
if (header_len + len >= sizeof(u.buffer)) {
stats.tx_oversize++;
return 0; /* drop this, it's too big */
}
/* copy payload into buffer */
memcpy(u.buffer + header_len, pack, len);
/* record and increment sequence numbers */
seq_sent = seq; seq++;
#ifdef PRINT_PACKETS
print_packet(2, u.buffer, header_len + len);
#endif
/* write this baby out to the net */
rc = (*my->write)(fd, u.buffer, header_len + len);
if (rc < 0) {
if (errno == ENOBUFS)
rc = 0; /* Simply ignore it */
stats.tx_failed++;
} else if ((size_t)rc < header_len + len) {
stats.tx_short++;
} else {
stats.tx_sent++;
stats.pt.seq = seq_sent;
stats.pt.time = time_now_usecs();
}
return rc;
}

53
pptp_gre.h Normal file
View File

@ -0,0 +1,53 @@
/* pptp_gre.h -- encapsulate PPP in PPTP-GRE.
* Handle the IP Protocol 47 portion of PPTP.
* C. Scott Ananian <cananian@alumni.princeton.edu>
*
* $Id: pptp_gre.h,v 1.6 2008/02/19 05:05:03 quozl Exp $
*/
#include "pptp_compat.h"
int pptp_gre_bind(struct in_addr inetaddr);
void pptp_gre_copy(u_int16_t call_id, u_int16_t peer_call_id,
int pty_fd, int gre_fd);
extern int syncppp;
extern int disable_buffer;
typedef struct pack_track {
uint32_t seq; // seq no of this tracked packet
uint64_t time; // time when this tracked packet was sent (in usecs)
} pack_track_t;
typedef struct gre_stats {
/* statistics for GRE receive */
uint32_t rx_accepted; // data packet was passed to pppd
uint32_t rx_lost; // data packet did not arrive before timeout
uint32_t rx_underwin; // data packet was under window (arrived too late
// or duplicate packet)
uint32_t rx_overwin; // data packet was over window
// (too many packets lost?)
uint32_t rx_buffered; // data packet arrived earlier than expected,
// packet(s) before it were lost or reordered
uint32_t rx_errors; // OS error on receive
uint32_t rx_truncated; // truncated packet
uint32_t rx_invalid; // wrong protocol or invalid flags
uint32_t rx_acks; // acknowledgement only
/* statistics for GRE transmit */
uint32_t tx_sent; // data packet write() to GRE socket succeeded
uint32_t tx_failed; // data packet write() to GRE socket returned error
uint32_t tx_short; // data packet write() to GRE socket underflowed
uint32_t tx_acks; // sent packet with just ACK
uint32_t tx_oversize; // data packet dropped because it was too large
/* statistics for packet tracking, for RTT calculation */
pack_track_t pt; // last data packet seq/time
int rtt; // estimated round-trip time in us
} gre_stats_t;
extern gre_stats_t stats;

304
pptp_msg.h Normal file
View File

@ -0,0 +1,304 @@
/* pptp.h: packet structures and magic constants for the PPTP protocol
* C. Scott Ananian <cananian@alumni.princeton.edu>
*
* $Id: pptp_msg.h,v 1.4 2008/02/19 05:05:03 quozl Exp $
*/
#ifndef INC_PPTP_H
#define INC_PPTP_H
/* Grab definitions of int16, int32, etc. */
#include <sys/types.h>
#include "pptp_compat.h"
/* define "portable" htons, etc. */
#define hton8(x) (x)
#define ntoh8(x) (x)
#define hton16(x) htons(x)
#define ntoh16(x) ntohs(x)
#define hton32(x) htonl(x)
#define ntoh32(x) ntohl(x)
/* PPTP magic numbers: ----------------------------------------- */
#define PPTP_MAGIC 0x1A2B3C4D /* Magic cookie for PPTP datagrams */
#define PPTP_PORT 1723 /* PPTP TCP port number */
#define PPTP_PROTO 47 /* PPTP IP protocol number */
/* Control Connection Message Types: --------------------------- */
#define PPTP_MESSAGE_CONTROL 1
#define PPTP_MESSAGE_MANAGE 2
/* Control Message Types: -------------------------------------- */
/* (Control Connection Management) */
#define PPTP_START_CTRL_CONN_RQST 1
#define PPTP_START_CTRL_CONN_RPLY 2
#define PPTP_STOP_CTRL_CONN_RQST 3
#define PPTP_STOP_CTRL_CONN_RPLY 4
#define PPTP_ECHO_RQST 5
#define PPTP_ECHO_RPLY 6
/* (Call Management) */
#define PPTP_OUT_CALL_RQST 7
#define PPTP_OUT_CALL_RPLY 8
#define PPTP_IN_CALL_RQST 9
#define PPTP_IN_CALL_RPLY 10
#define PPTP_IN_CALL_CONNECT 11
#define PPTP_CALL_CLEAR_RQST 12
#define PPTP_CALL_CLEAR_NTFY 13
/* (Error Reporting) */
#define PPTP_WAN_ERR_NTFY 14
/* (PPP Session Control) */
#define PPTP_SET_LINK_INFO 15
/* PPTP version information: --------------------------------------*/
#define PPTP_VERSION_STRING "1.00"
#define PPTP_VERSION 0x100
#define PPTP_FIRMWARE_STRING "0.01"
#define PPTP_FIRMWARE_VERSION 0x001
/* PPTP capabilities: ---------------------------------------------*/
/* (Framing capabilities for msg sender) */
#define PPTP_FRAME_ASYNC 1
#define PPTP_FRAME_SYNC 2
#define PPTP_FRAME_ANY 3
/* (Bearer capabilities for msg sender) */
#define PPTP_BEARER_ANALOG 1
#define PPTP_BEARER_DIGITAL 2
#define PPTP_BEARER_ANY 3
#define PPTP_RESULT_GENERAL_ERROR 2
/* (Reasons to close a connection) */
#define PPTP_STOP_NONE 1 /* no good reason */
#define PPTP_STOP_PROTOCOL 2 /* can't support peer's protocol version */
#define PPTP_STOP_LOCAL_SHUTDOWN 3 /* requester is being shut down */
/* PPTP datagram structures (all data in network byte order): ----------*/
struct pptp_header {
u_int16_t length; /* message length in octets, including header */
u_int16_t pptp_type; /* PPTP message type. 1 for control message. */
u_int32_t magic; /* this should be PPTP_MAGIC. */
u_int16_t ctrl_type; /* Control message type (0-15) */
u_int16_t reserved0; /* reserved. MUST BE ZERO. */
};
struct pptp_start_ctrl_conn { /* for control message types 1 and 2 */
struct pptp_header header;
u_int16_t version; /* PPTP protocol version. = PPTP_VERSION */
u_int8_t result_code; /* these two fields should be zero on rqst msg*/
u_int8_t error_code; /* 0 unless result_code==2 (General Error) */
u_int32_t framing_cap; /* Framing capabilities */
u_int32_t bearer_cap; /* Bearer Capabilities */
u_int16_t max_channels; /* Maximum Channels (=0 for PNS, PAC ignores) */
u_int16_t firmware_rev; /* Firmware or Software Revision */
u_int8_t hostname[64]; /* Host Name (64 octets, zero terminated) */
u_int8_t vendor[64]; /* Vendor string (64 octets, zero term.) */
/* MS says that end of hostname/vendor fields should be filled with */
/* octets of value 0, but Win95 PPTP driver doesn't do this. */
};
struct pptp_stop_ctrl_conn { /* for control message types 3 and 4 */
struct pptp_header header;
u_int8_t reason_result; /* reason for rqst, result for rply */
u_int8_t error_code; /* MUST be 0, unless rply result==2 (general err)*/
u_int16_t reserved1; /* MUST be 0 */
};
struct pptp_echo_rqst { /* for control message type 5 */
struct pptp_header header;
u_int32_t identifier; /* arbitrary value set by sender which is used */
/* to match up reply and request */
};
struct pptp_echo_rply { /* for control message type 6 */
struct pptp_header header;
u_int32_t identifier; /* should correspond to id of rqst */
u_int8_t result_code;
u_int8_t error_code; /* =0, unless result_code==2 (general error) */
u_int16_t reserved1; /* MUST BE ZERO */
};
struct pptp_out_call_rqst { /* for control message type 7 */
struct pptp_header header;
u_int16_t call_id; /* Call ID (unique id used to multiplex data) */
u_int16_t call_sernum; /* Call Serial Number (used for logging) */
u_int32_t bps_min; /* Minimum BPS (lowest acceptable line speed) */
u_int32_t bps_max; /* Maximum BPS (highest acceptable line speed) */
u_int32_t bearer; /* Bearer type */
u_int32_t framing; /* Framing type */
u_int16_t recv_size; /* Recv. Window Size (no. of buffered packets) */
u_int16_t delay; /* Packet Processing Delay (in 1/10 sec) */
u_int16_t phone_len; /* Phone Number Length (num. of valid digits) */
u_int16_t reserved1; /* MUST BE ZERO */
u_int8_t phone_num[64]; /* Phone Number (64 octets, null term.) */
u_int8_t subaddress[64]; /* Subaddress (64 octets, null term.) */
};
struct pptp_out_call_rply { /* for control message type 8 */
struct pptp_header header;
u_int16_t call_id; /* Call ID (used to multiplex data over tunnel)*/
u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/
u_int8_t result_code; /* Result Code (1 is no errors) */
u_int8_t error_code; /* Error Code (=0 unless result_code==2) */
u_int16_t cause_code; /* Cause Code (addt'l failure information) */
u_int32_t speed; /* Connect Speed (in BPS) */
u_int16_t recv_size; /* Recv. Window Size (no. of buffered packets) */
u_int16_t delay; /* Packet Processing Delay (in 1/10 sec) */
u_int32_t channel; /* Physical Channel ID (for logging) */
};
struct pptp_in_call_rqst { /* for control message type 9 */
struct pptp_header header;
u_int16_t call_id; /* Call ID (unique id used to multiplex data) */
u_int16_t call_sernum; /* Call Serial Number (used for logging) */
u_int32_t bearer; /* Bearer type */
u_int32_t channel; /* Physical Channel ID (for logging) */
u_int16_t dialed_len; /* Dialed Number Length (# of valid digits) */
u_int16_t dialing_len; /* Dialing Number Length (# of valid digits) */
u_int8_t dialed_num[64]; /* Dialed Number (64 octets, zero term.) */
u_int8_t dialing_num[64]; /* Dialing Number (64 octets, zero term.) */
u_int8_t subaddress[64]; /* Subaddress (64 octets, zero term.) */
};
struct pptp_in_call_rply { /* for control message type 10 */
struct pptp_header header;
u_int16_t call_id; /* Call ID (used to multiplex data over tunnel)*/
u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/
u_int8_t result_code; /* Result Code (1 is no errors) */
u_int8_t error_code; /* Error Code (=0 unless result_code==2) */
u_int16_t recv_size; /* Recv. Window Size (no. of buffered packets) */
u_int16_t delay; /* Packet Processing Delay (in 1/10 sec) */
u_int16_t reserved1; /* MUST BE ZERO */
};
struct pptp_in_call_connect { /* for control message type 11 */
struct pptp_header header;
u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/
u_int16_t reserved1; /* MUST BE ZERO */
u_int32_t speed; /* Connect Speed (in BPS) */
u_int16_t recv_size; /* Recv. Window Size (no. of buffered packets) */
u_int16_t delay; /* Packet Processing Delay (in 1/10 sec) */
u_int32_t framing; /* Framing type */
};
struct pptp_call_clear_rqst { /* for control message type 12 */
struct pptp_header header;
u_int16_t call_id; /* Call ID (used to multiplex data over tunnel)*/
u_int16_t reserved1; /* MUST BE ZERO */
};
struct pptp_call_clear_ntfy { /* for control message type 13 */
struct pptp_header header;
u_int16_t call_id; /* Call ID (used to multiplex data over tunnel)*/
u_int8_t result_code; /* Result Code */
u_int8_t error_code; /* Error Code (=0 unless result_code==2) */
u_int16_t cause_code; /* Cause Code (for ISDN, is Q.931 cause code) */
u_int16_t reserved1; /* MUST BE ZERO */
u_int8_t call_stats[128]; /* Call Statistics: 128 octets, ascii, 0-term */
};
struct pptp_wan_err_ntfy { /* for control message type 14 */
struct pptp_header header;
u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/
u_int16_t reserved1; /* MUST BE ZERO */
u_int32_t crc_errors; /* CRC errors */
u_int32_t frame_errors; /* Framing errors */
u_int32_t hard_errors; /* Hardware overruns */
u_int32_t buff_errors; /* Buffer overruns */
u_int32_t time_errors; /* Time-out errors */
u_int32_t align_errors; /* Alignment errors */
};
struct pptp_set_link_info { /* for control message type 15 */
struct pptp_header header;
u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst) */
u_int16_t reserved1; /* MUST BE ZERO */
u_int32_t send_accm; /* Send ACCM (for PPP packets; default 0xFFFFFFFF)*/
u_int32_t recv_accm; /* Receive ACCM (for PPP pack.;default 0xFFFFFFFF)*/
};
/* helpful #defines: -------------------------------------------- */
#define pptp_isvalid_ctrl(header, type, length) \
(!( ( ntoh16(((struct pptp_header *)header)->length) < (length) ) || \
( ntoh16(((struct pptp_header *)header)->pptp_type) !=(type) ) || \
( ntoh32(((struct pptp_header *)header)->magic) !=PPTP_MAGIC) || \
( ntoh16(((struct pptp_header *)header)->ctrl_type) > PPTP_SET_LINK_INFO) || \
( ntoh16(((struct pptp_header *)header)->reserved0) !=0 ) ))
#define PPTP_HEADER_CTRL(type) \
{ hton16(PPTP_CTRL_SIZE(type)), \
hton16(PPTP_MESSAGE_CONTROL), \
hton32(PPTP_MAGIC), \
hton16(type), 0 }
#define PPTP_CTRL_SIZE(type) ( \
(type==PPTP_START_CTRL_CONN_RQST)?sizeof(struct pptp_start_ctrl_conn): \
(type==PPTP_START_CTRL_CONN_RPLY)?sizeof(struct pptp_start_ctrl_conn): \
(type==PPTP_STOP_CTRL_CONN_RQST )?sizeof(struct pptp_stop_ctrl_conn): \
(type==PPTP_STOP_CTRL_CONN_RPLY )?sizeof(struct pptp_stop_ctrl_conn): \
(type==PPTP_ECHO_RQST )?sizeof(struct pptp_echo_rqst): \
(type==PPTP_ECHO_RPLY )?sizeof(struct pptp_echo_rply): \
(type==PPTP_OUT_CALL_RQST )?sizeof(struct pptp_out_call_rqst): \
(type==PPTP_OUT_CALL_RPLY )?sizeof(struct pptp_out_call_rply): \
(type==PPTP_IN_CALL_RQST )?sizeof(struct pptp_in_call_rqst): \
(type==PPTP_IN_CALL_RPLY )?sizeof(struct pptp_in_call_rply): \
(type==PPTP_IN_CALL_CONNECT )?sizeof(struct pptp_in_call_connect): \
(type==PPTP_CALL_CLEAR_RQST )?sizeof(struct pptp_call_clear_rqst): \
(type==PPTP_CALL_CLEAR_NTFY )?sizeof(struct pptp_call_clear_ntfy): \
(type==PPTP_WAN_ERR_NTFY )?sizeof(struct pptp_wan_err_ntfy): \
(type==PPTP_SET_LINK_INFO )?sizeof(struct pptp_set_link_info): \
0)
#define max(a,b) (((a)>(b))?(a):(b))
#define PPTP_CTRL_SIZE_MAX ( \
max(sizeof(struct pptp_start_ctrl_conn), \
max(sizeof(struct pptp_echo_rqst), \
max(sizeof(struct pptp_echo_rply), \
max(sizeof(struct pptp_out_call_rqst), \
max(sizeof(struct pptp_out_call_rply), \
max(sizeof(struct pptp_in_call_rqst), \
max(sizeof(struct pptp_in_call_rply), \
max(sizeof(struct pptp_in_call_connect), \
max(sizeof(struct pptp_call_clear_rqst), \
max(sizeof(struct pptp_call_clear_ntfy), \
max(sizeof(struct pptp_wan_err_ntfy), \
max(sizeof(struct pptp_set_link_info), 0)))))))))))))
/* gre header structure: -------------------------------------------- */
#define PPTP_GRE_PROTO 0x880B
#define PPTP_GRE_VER 0x1
#define PPTP_GRE_FLAG_C 0x80
#define PPTP_GRE_FLAG_R 0x40
#define PPTP_GRE_FLAG_K 0x20
#define PPTP_GRE_FLAG_S 0x10
#define PPTP_GRE_FLAG_A 0x80
#define PPTP_GRE_IS_C(f) ((f)&PPTP_GRE_FLAG_C)
#define PPTP_GRE_IS_R(f) ((f)&PPTP_GRE_FLAG_R)
#define PPTP_GRE_IS_K(f) ((f)&PPTP_GRE_FLAG_K)
#define PPTP_GRE_IS_S(f) ((f)&PPTP_GRE_FLAG_S)
#define PPTP_GRE_IS_A(f) ((f)&PPTP_GRE_FLAG_A)
struct pptp_gre_header {
u_int8_t flags; /* bitfield */
u_int8_t ver; /* should be PPTP_GRE_VER (enhanced GRE) */
u_int16_t protocol; /* should be PPTP_GRE_PROTO (ppp-encaps) */
u_int16_t payload_len; /* size of ppp payload, not inc. gre header */
u_int16_t call_id; /* peer's call_id for this session */
u_int32_t seq; /* sequence number. Present if S==1 */
u_int32_t ack; /* seq number of highest packet recieved by */
/* sender in this session */
};
#endif /* INC_PPTP_H */

41
pptp_options.h Normal file
View File

@ -0,0 +1,41 @@
/* pptp_options.h ...... various constants used in the PPTP protocol.
* #define STANDARD to emulate NT 4.0 exactly.
* C. Scott Ananian <cananian@alumni.princeton.edu>
*
* $Id: pptp_options.h,v 1.3 2004/11/09 01:42:32 quozl Exp $
*/
#ifndef INC_PPTP_OPTIONS_H
#define INC_PPTP_OPTIONS_H
#undef PPTP_FIRMWARE_STRING
#undef PPTP_FIRMWARE_VERSION
#define PPTP_BUF_MAX 65536
#define PPTP_TIMEOUT 60 /* seconds */
extern int idle_wait;
extern int max_echo_wait;
#define PPTP_CONNECT_SPEED 10000000
#define PPTP_WINDOW 3
#define PPTP_DELAY 0
#define PPTP_BPS_MIN 2400
#define PPTP_BPS_MAX 10000000
#ifndef STANDARD
#define PPTP_MAX_CHANNELS 65535
#define PPTP_FIRMWARE_STRING "0.01"
#define PPTP_FIRMWARE_VERSION 0x001
#define PPTP_HOSTNAME {'l','o','c','a','l',0}
#define PPTP_VENDOR {'c','a','n','a','n','i','a','n',0}
#define PPTP_FRAME_CAP PPTP_FRAME_ANY
#define PPTP_BEARER_CAP PPTP_BEARER_ANY
#else
#define PPTP_MAX_CHANNELS 5
#define PPTP_FIRMWARE_STRING "0.01"
#define PPTP_FIRMWARE_VERSION 0
#define PPTP_HOSTNAME {'l','o','c','a','l',0}
#define PPTP_VENDOR {'N','T',0}
#define PPTP_FRAME_CAP 2
#define PPTP_BEARER_CAP 1
#endif
#endif /* INC_PPTP_OPTIONS_H */

54
pptp_quirks.c Normal file
View File

@ -0,0 +1,54 @@
/* pptp_quirks.c ...... various options to fix quirks found in buggy adsl modems
* mulix <mulix@actcom.co.il>
*
* $Id: pptp_quirks.c,v 1.3 2011/12/19 07:15:03 quozl Exp $
*/
#include <string.h>
#include "orckit_quirks.h"
#include "pptp_quirks.h"
static int quirk_index = -1;
struct pptp_fixup pptp_fixups[] = {
{BEZEQ_ISRAEL, ORCKIT, ORCKIT_ATUR3,
orckit_atur3_build_hook,
orckit_atur3_start_ctrl_conn_hook,
orckit_atur3_set_link_hook}
};
static int fixups_sz = sizeof(pptp_fixups)/sizeof(pptp_fixups[0]);
/* return 0 on success, non 0 otherwise */
int set_quirk_index(int index)
{
if (index >= 0 && index < fixups_sz) {
quirk_index = index;
return 0;
}
return -1;
}
int get_quirk_index(void)
{
return quirk_index;
}
/* return the index for this isp in the quirks table, -1 if not found */
int find_quirk(const char* isp_name)
{
int i = 0;
if (isp_name) {
while (i < fixups_sz && pptp_fixups[i].isp) {
if (!strcmp(pptp_fixups[i].isp, isp_name)) {
return i;
}
++i;
}
}
return -1;
}

59
pptp_quirks.h Normal file
View File

@ -0,0 +1,59 @@
/* pptp_quirks.h ...... various options to fix quirks found in buggy adsl modems
* mulix <mulix@actcom.co.il>
*
* $Id: pptp_quirks.h,v 1.2 2011/12/19 07:15:03 quozl Exp $
*/
#ifndef INC_PPTP_QUIRKS_H
#define INC_PPTP_QUIRKS_H
/* isp defs - correspond to slots in the fixups table */
#define BEZEQ_ISRAEL "BEZEQ_ISRAEL"
/* vendor defs */
#define ORCKIT 1
#define ALCATEL 2
/* device defs */
#define ORCKIT_ATUR2 1
#define ORCKIT_ATUR3 2
#include "pptp_msg.h"
#include "pptp_ctrl.h"
struct pptp_fixup {
const char* isp; /* which isp? e.g. Bezeq in Israel */
int vendor; /* which vendor? e.g. Orckit */
int device; /* which device? e.g. Orckit Atur3 */
/* use this hook to build your own out call request packet */
int (*out_call_rqst_hook)(struct pptp_out_call_rqst* packet);
/* use this hook to build your own start control connection packet */
/* note that this hook is called from two different places, depending
on whether this is a request or reply */
int (*start_ctrl_conn)(struct pptp_start_ctrl_conn* packet);
/* use this hook if you need to send a 'set_link' packet once
the connection is established */
int (*set_link_hook)(struct pptp_set_link_info* packet,
int peer_call_id);
};
extern struct pptp_fixup pptp_fixups[];
/* find the index for this isp in the quirks table */
/* return the index on success, -1 if not found */
int find_quirk(const char* isp_name);
/* set the global quirk index. return 0 on success, non 0 otherwise */
int set_quirk_index(int index);
/* get the global quirk index. return the index on success,
-1 if no quirk is defined */
int get_quirk_index(void);
#endif /* INC_PPTP_QUIRKS_H */

277
pptpsetup Normal file
View File

@ -0,0 +1,277 @@
#!/usr/bin/perl
use strict;
use Getopt::Long;
use vars qw($VERSION);
$VERSION = '0.03';
# Command-line parameters:
# actions
my ( $_create, $_delete, $_help );
# values
my ( $SERVER, $DOMAIN, $USERNAME, $PASSWORD, $ENCRYPT, $START );
my $result = GetOptions(
"create|c=s" => \$_create, # --create foo -> &create("foo")
"delete=s" => \$_delete, # --delete foo -> &delete("foo")
"help|h" => \$_help, # --help -> &help()
"server|s=s" => \$SERVER,
"domain|d=s" => \$DOMAIN,
"username|u=s" => \$USERNAME,
"password|p=s" => \$PASSWORD,
"encrypt|e" => \$ENCRYPT,
"start" => \$START,
);
if ($_create) {
&create($_create);
} elsif ($_delete) {
&delete($_delete);
} elsif ($_help) {
&help();
} else {
die "$0: too few arguments.\nTry '$0 --help' for more information.\n";
}
exit;
####
sub create {
my $TUNNEL = shift;
# input validation
($TUNNEL) = $TUNNEL =~ m{^(\w+)$}
or die "$0: invalid tunnel name.\nTry '$0 --help' for more information.\n";
($SERVER) = $SERVER =~ m{^(.+)$}
or die "$0: invalid server.\nTry '$0 --help' for more information.\n";
($USERNAME) = $USERNAME =~ m{^(.+)$}
or die "$0: invalid username.\nTry '$0 --help' for more information.\n";
# ask password
if ( !$PASSWORD ) {
print "Password: ";
$PASSWORD = <STDIN>;
$PASSWORD =~ s/([^\x20\x21\x23-\x7e])/sprintf ("\\x%02x", ord ($1))/eg;
}
# put '\' between domain and username IF specified a domain
$DOMAIN = "$DOMAIN\\" if $DOMAIN;
# create or add lines to the /etc/ppp/chap-secrets file,
# which holds usernames and passwords
my $chap_secrets_file = '/etc/ppp/chap-secrets';
umask( 0027 );
open( FILE, ">>", $chap_secrets_file )
or die "$0: can't write to '$chap_secrets_file': $!\n";
print FILE "\n";
print FILE "# added by pptpsetup for $TUNNEL\n";
print FILE "$DOMAIN$USERNAME $TUNNEL \"$PASSWORD\" *\n";
close FILE;
# create a /etc/ppp/peers/$TUNNEL file
my $tunnel_file = "/etc/ppp/peers/$TUNNEL";
open( FILE, ">$tunnel_file" )
or die "$0: can't write to '$tunnel_file': $!\n";
print FILE <<"TUNNEL";
# written by pptpsetup
pty "/usr/sbin/pptp $SERVER --nolaunchpppd"
lock
noauth
nobsdcomp
nodeflate
name $DOMAIN$USERNAME
remotename $TUNNEL
ipparam $TUNNEL
TUNNEL
print FILE "require-mppe-128\n" if $ENCRYPT;
close FILE;
# start tunneling
if ($START) {
system("pppd call $TUNNEL updetach");
}
}
####
sub help {
print <<'EOF';
pptpsetup --create <TUNNEL> --server <SERVER> [--domain <DOMAIN>]
--username <USERNAME> [--password <PASSWORD>]
[--encrypt] [--start]
pptpsetup --delete <TUNNEL>
Options:
* the name you wish to use to refer to the tunnel (you choose it),
* the IP address or host name of the server,
* the authentication domain name (optional),
* the username you are to use,
* the password you are to use,
* whether encryption is required,
* whether to start the connection after configuration.
pptpsetup - Point-to-Point Tunneling Protocol setup
Copyright (C) 2006 Free Software Foundation
pptpsetup comes with ABSOLUTELY NO WARRANTY; for details see source.
This is free software, and you are welcome to redistribute it
under certain conditions; see source for details.
Written by Nelson Ferraz.
EOF
exit;
}
####
sub delete {
my $tunnel = shift;
# input validation
($tunnel) = $tunnel =~ m{^(\w+)$}
or die "$0: invalid tunnel name.\nTry '$0 --help' for more information.\n";
# delete tunnel file
my $tunnel_file = "/etc/ppp/peers/$tunnel";
unlink $tunnel_file
or die "$0: can't delete '$tunnel_file': $!\n";
# delete entry from chap-secrets
my $chap_file = '/etc/ppp/chap-secrets';
my $mode = (stat($chap_file))[2] & 07777;
open( FILE, $chap_file )
or die "$0: can't read '$chap_file': $!\n";
my @chap = <FILE>;
close FILE;
my $new_chap = '';
foreach (@chap) {
$new_chap .= $_ unless /\b$tunnel\b/;
}
# backup
rename( $chap_file, "$chap_file.bkp" );
# write new chap-secrets
open( FILE, ">$chap_file" )
or die "$0: can't write '$chap_file': $!\n";
chmod $mode, $chap_file;
print FILE $new_chap;
close FILE;
exit;
}
__END__
=head1 NAME
pptpsetup - Point-to-Point Tunneling Protocol setup
=head1 SYNOPSIS
pptpsetup --create <TUNNEL> --server <SERVER> [--domain <DOMAIN>]
--username <USERNAME> [--password <PASSWORD>]
[--encrypt] [--start]
pptpsetup --delete <TUNNEL>
=head1 DESCRIPTION
PPTP Client is a Linux, FreeBSD, NetBSD and OpenBSD client for the
proprietary Microsoft Point-to-Point Tunneling Protocol, PPTP.
This script configures PPTP Client on Linux.
=head1 OPTIONS
=over 16
=item --create TUNNEL
create a tunnel named TUNNEL
=item --delete TUNNEL
delete the file /etc/ppp/peers/TUNNEL and any lines from
/etc/ppp/chap-secrets that contains "TUNNEL" as a single word
=item --server SERVER
the IP address or host name of the server
=item --domain DOMAIN
the authentication domain name (optional)
=item --username USERNAME
the username you are to use
=item --password PASSWORD
the password you are to use. If you don't specify a password,
pptpsetup will ask for one.
=item --encrypt
whether encryption is required
=item --start
whether the connection should be started after configuration.
=back
=head1 AUTHOR
Nelson Ferraz <nferraz at gmail.com>,
based on James Cameron's PPTP Client Debian HOWTO.
=head1 SEE ALSO
=over 16
=item PPTP Client Debian HOWTO
http://pptpclient.sourceforge.net/howto-debian.phtml
=item PPTP Client Diagnosis HOWTO
http://pptpclient.sourceforge.net/howto-diagnosis.phtml
=back
=head1 COPYRIGHT
pptpsetup - Point-to-Point Tunneling Protocol setup
Copyright (C) 2006 Nelson Ferraz
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

243
pqueue.c Normal file
View File

@ -0,0 +1,243 @@
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "util.h" // for log()
#include "pqueue.h"
#ifdef DEBUG_PQUEUE
#define DEBUG_ON 1
#else
#define DEBUG_ON 0
#endif
#define DEBUG_CMD(_a) if (DEBUG_ON) { _a }
#define MIN_CAPACITY 128 /* min allocated buffer for a packet */
static int pqueue_alloc (u_int32_t seq, unsigned char *packet, int packlen, pqueue_t **new);
int packet_timeout_usecs = DEFAULT_PACKET_TIMEOUT * 1000000;
static pqueue_t *pq_head = NULL, *pq_tail = NULL;
/* contains a list of free queue elements.*/
static pqueue_t *pq_freelist_head = NULL;
static void pq_freelist_add(pqueue_t *point) {
/* add point to the freelist */
point->next = pq_freelist_head;
point->prev = NULL;
if (point->next)
point->next->prev = point;
pq_freelist_head = point;
}
static int pqueue_alloc(u_int32_t seq, unsigned char *packet, int packlen, pqueue_t **new) {
pqueue_t *newent;
DEBUG_CMD(log("seq=%d, packlen=%d", seq, packlen););
/* search the freelist for one that has sufficient space */
if (pq_freelist_head) {
for (newent = pq_freelist_head; newent; newent = newent->next) {
if (newent->capacity >= packlen) {
/* unlink from freelist */
if (pq_freelist_head == newent)
pq_freelist_head = newent->next;
if (newent->prev)
newent->prev->next = newent->next;
if (newent->next)
newent->next->prev = newent->prev;
if (pq_freelist_head)
pq_freelist_head->prev = NULL;
break;
} /* end if capacity >= packlen */
} /* end for */
/* nothing found? Take first and reallocate it */
if (NULL == newent) {
newent = pq_freelist_head;
pq_freelist_head = pq_freelist_head->next;
if (pq_freelist_head)
pq_freelist_head->prev = NULL;
DEBUG_CMD(log("realloc capacity %d to %d",newent->capacity, packlen););
newent->packet = (unsigned char *)realloc(newent->packet, packlen);
if (!newent->packet) {
warn("error reallocating packet: %s", strerror(errno));
return -1;
}
newent->capacity = packlen;
}
DEBUG_CMD(log("Recycle entry from freelist. Capacity: %d", newent->capacity););
} else {
/* allocate a new one */
newent = (pqueue_t *)malloc( sizeof(pqueue_t) );
if (!newent) {
warn("error allocating newent: %s", strerror(errno));
return -1;
}
newent->capacity = 0;
DEBUG_CMD(log("Alloc new queue entry"););
}
if ( ! newent->capacity ) {
/* a new queue entry was allocated. Allocate the packet buffer */
int size = packlen < MIN_CAPACITY ? MIN_CAPACITY : packlen;
/* Allocate at least MIN_CAPACITY */
DEBUG_CMD(log("allocating for packet size %d", size););
newent->packet = (unsigned char *)malloc(size);
if (!newent->packet) {
warn("error allocating packet: %s", strerror(errno));
return -1;
}
newent->capacity = size;
} /* endif ! capacity */
assert( newent->capacity >= packlen );
/* store the contents into the buffer */
memcpy(newent->packet, packet, packlen);
newent->next = newent->prev = NULL;
newent->seq = seq;
newent->packlen = packlen;
gettimeofday(&newent->expires, NULL);
newent->expires.tv_usec += packet_timeout_usecs;
newent->expires.tv_sec += (newent->expires.tv_usec / 1000000);
newent->expires.tv_usec %= 1000000;
*new = newent;
return 0;
}
int pqueue_add (u_int32_t seq, unsigned char *packet, int packlen) {
pqueue_t *newent, *point;
/* get a new entry */
if ( 0 != pqueue_alloc(seq, packet, packlen, &newent) ) {
return -1;
}
for (point = pq_head; point != NULL; point = point->next) {
if (point->seq == seq) {
// queue already contains this packet
warn("discarding duplicate packet %d", seq);
pq_freelist_add(point);
return -1;
}
if (point->seq > seq) {
// gone too far: point->seq > seq and point->prev->seq < seq
if (point->prev) {
// insert between point->prev and point
DEBUG_CMD(log("adding %d between %d and %d",
seq, point->prev->seq, point->seq););
point->prev->next = newent;
} else {
// insert at head of queue, before point
DEBUG_CMD(log("adding %d before %d", seq, point->seq););
pq_head = newent;
}
newent->prev = point->prev; // will be NULL, at head of queue
newent->next = point;
point->prev = newent;
return 0;
}
}
/* We didn't find anywhere to insert the packet,
* so there are no packets in the queue with higher sequences than this one,
* so all the packets in the queue have lower sequences,
* so this packet belongs at the end of the queue (which might be empty)
*/
if (pq_head == NULL) {
DEBUG_CMD(log("adding %d to empty queue", seq););
pq_head = newent;
} else {
DEBUG_CMD(log("adding %d as tail, after %d", seq, pq_tail->seq););
pq_tail->next = newent;
}
newent->prev = pq_tail;
pq_tail = newent;
return 0;
}
int pqueue_del (pqueue_t *point) {
DEBUG_CMD(log("Move seq %d to freelist", point->seq););
/* unlink from pq */
if (pq_head == point) pq_head = point->next;
if (pq_tail == point) pq_tail = point->prev;
if (point->prev) point->prev->next = point->next;
if (point->next) point->next->prev = point->prev;
/* add point to the freelist */
pq_freelist_add(point);
DEBUG_CMD(
int pq_count = 0;
int pq_freelist_count = 0;
pqueue_t *dpoint;
for (dpoint = pq_head; dpoint ; dpoint = dpoint->next) {
++pq_count;
}
for (dpoint = pq_freelist_head; dpoint ; dpoint = dpoint->next) {
++pq_freelist_count;
}
log("queue length is %d, freelist length is %d", pq_count,
pq_freelist_count);
);
return 0;
}
pqueue_t *pqueue_head (void) {
return pq_head;
}
int pqueue_expiry_time (pqueue_t *entry) {
struct timeval tv;
int expiry_time;
gettimeofday(&tv, NULL);
expiry_time = (entry->expires.tv_sec - tv.tv_sec) * 1000000;
expiry_time += (entry->expires.tv_usec - tv.tv_usec);
return expiry_time;
}

34
pqueue.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef PQUEUE_H
#define PQUEUE_H
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
/* wait this many seconds for missing packets before forgetting about them */
#define DEFAULT_PACKET_TIMEOUT 0.3
extern int packet_timeout_usecs;
/* assume packet is bad/spoofed if it's more than this many seqs ahead */
/* default is NOT to check - command line override via '--missing-window <n>' */
/* default value is 300 - recommended is 6000 for high speed data rates */
#define MISSING_WINDOW -1
extern int missing_window;
/* Packet queue structure: linked list of packets received out-of-order */
typedef struct pqueue {
struct pqueue *next;
struct pqueue *prev;
u_int32_t seq;
struct timeval expires;
unsigned char *packet;
int packlen;
int capacity;
} pqueue_t;
int pqueue_add (u_int32_t seq, unsigned char *packet, int packlen);
int pqueue_del (pqueue_t *point);
pqueue_t *pqueue_head (void);
int pqueue_expiry_time (pqueue_t *entry);
#endif /* PQUEUE_H */

195
routing.c Normal file
View File

@ -0,0 +1,195 @@
/*
routing.c, manipulating routing table for PPTP Client
Copyright (C) 2006 Free Software Foundation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA
*/
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include "routing.h"
#include "config.h"
#if defined (__SVR4) && defined (__sun) /* Solaris */
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <errno.h>
#include "util.h"
/* PF_ROUTE socket*/
int rts;
/* Destination and gateway addresses */
struct sockaddr_in rdst, rgw;
/* Request sequence */
int rseq;
int dorouting;
#else /* Solaris */
/* route to the server */
char *route;
#endif /* Solaris */
/*
Design discussion.
The primary task of this module is to add a host route to the PPTP
server so that the kernel continues to deliver PPTP control and data
connection packets to the server despite the new PPP interface that is
created. The flag --nohostroute is to disable this.
A secondary task may be to implement all-to-tunnel routing if the
appropriate flag is specified on the command line. The flag
--route-all is to implement this (not yet implemented).
Caveat.
It is not possible from the "ip route" command to determine if a host
route already exists, so it isn't practical to put the routing table
back exactly as it was.
We have a choice of either leaving our route lying around, or
destroying a route that the user had pre-arranged. Both are
unfortunate. The flag --remove-host-route is to remove the route
regardless (not yet implemented).
*/
void routing_init(char *ip) {
#if defined (__SVR4) && defined (__sun) /* Solaris */
rdst.sin_family = AF_INET;
if ( ! inet_pton(AF_INET, ip, &rdst.sin_addr) ) {
log("Cannot convert address: %s", strerror(errno));
return;
}
if ( (rts = socket(PF_ROUTE, SOCK_RAW, AF_INET )) < 0 ) {
log("Cannot open routing socket: %s", strerror(errno));
return;
}
struct rt_msg rtm = {
.hdr.rtm_msglen = sizeof(struct rt_msg),
.hdr.rtm_version = RTM_VERSION,
.hdr.rtm_type = RTM_GET,
.hdr.rtm_addrs = RTA_DST,
.hdr.rtm_pid = getpid(),
.hdr.rtm_seq = ++rseq,
.addrs[RTAX_DST] = rdst
};
if ( write(rts, &rtm, rtm.hdr.rtm_msglen) != rtm.hdr.rtm_msglen ) {
log("Error writing to routing socket: %s", strerror(errno));
close(rts);
return;
}
while ( read(rts, &rtm, sizeof(struct rt_msg)) > 0 )
if ( rtm.hdr.rtm_pid == getpid() && rtm.hdr.rtm_seq == rseq) {
/* Check if host route already present */
if ( ( rtm.hdr.rtm_flags & RTF_HOST ) != RTF_HOST ) {
rgw = rtm.addrs[RTAX_GATEWAY];
dorouting = 1;
}
break;
}
#endif /* Solaris */
#if defined(__linux)
char buf[256];
char tbuf[256];
const char *uid;
FILE *p;
snprintf(buf, 255, "%s route get %s", IP_BINARY, ip);
p = popen(buf, "r");
fgets(buf, 255, p);
/* TODO: check for failure of fgets */
uid = strstr(buf, " uid");
if (uid) {
snprintf(tbuf, uid - buf + 1, "%s", buf);
route = strdup(tbuf);
} else {
route = strdup(buf);
}
pclose(p);
/* TODO: check for failure of command */
#endif /* __linux__ */
}
void routing_start(void) {
#if defined (__SVR4) && defined (__sun) /* Solaris */
if ( ! dorouting )
return;
struct rt_msg rtm = {
.hdr.rtm_msglen = sizeof(struct rt_msg),
.hdr.rtm_version = RTM_VERSION,
.hdr.rtm_type = RTM_ADD,
.hdr.rtm_flags = RTF_HOST | RTF_GATEWAY | RTF_STATIC,
.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY,
.hdr.rtm_pid = getpid(),
.hdr.rtm_seq = ++rseq,
.addrs[RTAX_DST] = rdst,
.addrs[RTAX_GATEWAY] = rgw
};
if ( write(rts, &rtm, rtm.hdr.rtm_msglen) != rtm.hdr.rtm_msglen ) {
log("Error adding route: %s", strerror(errno));
}
#endif
#if defined(__linux__)
char buf[256];
FILE *p;
snprintf(buf, 255, "%s route replace %s", IP_BINARY, route);
p = popen(buf, "r");
pclose(p);
#endif /* __linux__ */
}
void routing_end(void) {
#if defined (__SVR4) && defined (__sun) /* Solaris */
if ( ! dorouting)
return;
struct rt_msg rtm = {
.hdr.rtm_msglen = sizeof(struct rt_msg),
.hdr.rtm_version = RTM_VERSION,
.hdr.rtm_type = RTM_DELETE,
.hdr.rtm_flags = RTF_HOST | RTF_GATEWAY | RTF_STATIC,
.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY,
.hdr.rtm_pid = getpid(),
.hdr.rtm_seq = ++rseq,
.addrs[RTAX_DST] = rdst,
.addrs[RTAX_GATEWAY] = rgw
};
if ( write(rts, &rtm, rtm.hdr.rtm_msglen) != rtm.hdr.rtm_msglen ) {
log("Error deleting route: %s", strerror(errno));
}
#endif /* Solaris */
#if defined(__linux__)
char buf[256];
FILE *p;
snprintf(buf, 255, "%s route delete %s", IP_BINARY, route);
p = popen(buf, "r");
pclose(p);
#endif /* __linux__ */
}

11
routing.h Normal file
View File

@ -0,0 +1,11 @@
#if defined (__SVR4) && defined (__sun) /* Solaris */
#include <netinet/in.h>
#include <net/route.h>
struct rt_msg {
struct rt_msghdr hdr;
struct sockaddr_in addrs[RTAX_MAX];
};
#endif /* Solaris */
void routing_init(char *ip);
void routing_start(void);
void routing_end(void);

184
test-redirections.c Normal file
View File

@ -0,0 +1,184 @@
/*
Packet reordering test implementation, intended to cause packets to be
reordered for testing pptpd and other servers. Avoids the use of
pqueue.c so that it can be tested independently.
*/
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
#include "test-redirections.h"
/* whether we are asked to test ordering, obtained from command line */
extern int test_type;
/* rate at which to do test ordering changes */
extern int test_rate;
/* trigger cycle */
static int test_ordering_cycle = 0;
/* phase of reordering */
static int test_ordering_phase = 0;
/* swap a packet every now and then */
static ssize_t write_reordered_swap(int fd, const void *buf, size_t count)
{
static void *pocket_buf = NULL;
static int pocket_count = 0;
int stat;
switch (test_ordering_phase) {
case 0: /* between triggers, send as normal */
test_ordering_cycle++;
if (test_ordering_cycle == test_rate) test_ordering_phase++;
return write(fd, buf, count);
case 1: /* triggered, swap a packet */
test_ordering_cycle++;
if (test_ordering_cycle == (test_rate+1)) {
/* pocket the packet */
pocket_count = count;
pocket_buf = malloc(count);
memcpy(pocket_buf, buf, count);
log("test order swap, packet buffered");
/* lie about the result */
return count;
} else {
/* after this, reset to normal */
test_ordering_cycle = 0;
test_ordering_phase = 0;
/* send the new packet first */
stat = write(fd, buf, count);
if ((size_t)stat != count) return stat;
/* then send the old packet next */
stat = write(fd, pocket_buf, pocket_count);
free(pocket_buf);
log("test order swap, packets sent");
return count;
}
default:
return write(fd, buf, count);
}
}
/* hold ten packets and send the eleventh, then the ten in order */
static ssize_t write_reordered_retransmit(int fd, const void *buf, size_t count)
{
int test_length = 10;
static void *pocket_buf[10];
static int pocket_count[10];
int stat, n;
switch (test_ordering_phase) {
case 0: /* between triggers, send as normal */
test_ordering_cycle++;
if (test_ordering_cycle == test_rate) test_ordering_phase++;
return write(fd, buf, count);
case 1: /* triggered, buffer the packets */
test_ordering_cycle++;
if (test_ordering_cycle == (test_rate+test_length)) {
test_ordering_phase = 2;
}
/* pocket the packet */
n = test_ordering_cycle - test_rate - 1;
pocket_count[n] = count;
pocket_buf[n] = malloc(count);
memcpy(pocket_buf[n], buf, count);
log("test order retransmit, packet buffered");
/* lie about the result */
return count;
case 2:
/* after this, reset to normal */
test_ordering_cycle = 0;
test_ordering_phase = 0;
/* send the new packet first */
stat = write(fd, buf, count);
if ((size_t)stat != count) return stat;
/* send the buffered packets in normal order */
for (n=0; n<test_length; n++) {
stat = write(fd, pocket_buf[n], pocket_count[n]);
/* ignores failures */
free(pocket_buf[n]);
}
log("test order retransmit, packets sent");
return count;
default:
return write(fd, buf, count);
}
}
/* hold ten packets and send them in reverse order */
static ssize_t write_reordered_reverse(int fd, const void *buf, size_t count)
{
int test_length = 10;
static void *pocket_buf[10];
static int pocket_count[10];
int stat, n;
switch (test_ordering_phase) {
case 0: /* between triggers, send as normal */
test_ordering_cycle++;
if (test_ordering_cycle == test_rate) test_ordering_phase++;
return write(fd, buf, count);
case 1: /* triggered, buffer the packets */
test_ordering_cycle++;
if (test_ordering_cycle == (test_rate+test_length)) {
test_ordering_phase = 2;
}
/* pocket the packet */
n = test_ordering_cycle - test_rate - 1;
pocket_count[n] = count;
pocket_buf[n] = malloc(count);
memcpy(pocket_buf[n], buf, count);
log("test order reverse, packet buffered");
/* lie about the result */
return count;
case 2:
/* after this, reset to normal */
test_ordering_cycle = 0;
test_ordering_phase = 0;
/* send the new packet first */
stat = write(fd, buf, count);
if ((size_t)stat != count) return stat;
/* send the buffered packets in reverse order */
for (n=test_length-1; n>0; n--) {
stat = write(fd, pocket_buf[n], pocket_count[n]);
/* ignores failures */
free(pocket_buf[n]);
}
log("test order reverse, packets sent");
return count;
default:
return write(fd, buf, count);
}
}
/* dispatcher for write reordering tests */
static ssize_t write_reordered(int fd, const void *buf, size_t count)
{
switch (test_type) {
case 1: /* swap a packet every now and then */
return write_reordered_swap(fd, buf, count);
case 2: /* hold ten packets and send the eleventh, then the ten in order */
return write_reordered_retransmit(fd, buf, count);
case 3: /* hold ten packets and send them in reverse order */
return write_reordered_reverse(fd, buf, count);
default:
return write(fd, buf, count);
}
}
struct test_redirections *test_redirections(void)
{
static struct test_redirections *my = NULL;
if (my == NULL) my = malloc(sizeof(struct test_redirections));
my->write = write;
if (test_type) my->write = write_reordered;
return my;
}

5
test-redirections.h Normal file
View File

@ -0,0 +1,5 @@
struct test_redirections {
ssize_t (*write)(int fd, const void *buf, size_t count);
};
struct test_redirections *test_redirections(void);

154
util.c Normal file
View File

@ -0,0 +1,154 @@
/* util.c ....... error message utilities.
* C. Scott Ananian <cananian@alumni.princeton.edu>
*
* $Id: util.c,v 1.13 2011/12/19 07:15:03 quozl Exp $
*/
#include <stdio.h>
#include <stdarg.h>
#include <syslog.h>
#include <unistd.h>
#include <stdlib.h>
#include "util.h"
#ifndef PROGRAM_NAME
#define PROGRAM_NAME "pptp"
#endif
/* implementation of log_string, defined as extern in util.h */
const char *log_string = "anon";
static void open_log(void) __attribute__ ((constructor));
static void close_log(void) __attribute__ ((destructor));
#define MAKE_STRING(label) \
va_list ap; \
char buf[256], string[256]; \
va_start(ap, format); \
vsnprintf(buf, sizeof(buf), format, ap); \
snprintf(string, sizeof(string), "%s %s[%s:%s:%d]: %s", \
log_string, label, func, file, line, buf); \
va_end(ap)
/*** open log *****************************************************************/
static void open_log(void) {
openlog(PROGRAM_NAME, LOG_PID, LOG_DAEMON);
}
/*** close log ****************************************************************/
static void close_log(void)
{
closelog();
}
/*** print a message to syslog ************************************************/
void _log(const char *func, const char *file, int line, const char *format, ...)
{
MAKE_STRING("log");
syslog(LOG_NOTICE, "%s", string);
}
/*** print a warning to syslog ************************************************/
void _warn(const char *func, const char *file, int line, const char *format, ...)
{
MAKE_STRING("warn");
fprintf(stderr, "%s\n", string);
syslog(LOG_WARNING, "%s", string);
}
/*** print a fatal warning to syslog and exit *********************************/
void _fatal(const char *func, const char *file, int line, const char *format, ...)
{
MAKE_STRING("fatal");
fprintf(stderr, "%s\n", string);
syslog(LOG_CRIT, "%s", string);
exit(1);
}
/*** connect a file to a file descriptor **************************************/
int file2fd(const char *path, const char *mode, int fd)
{
int ok = 0;
FILE *file = NULL;
file = fopen(path, mode);
if (file != NULL && dup2(fileno(file), fd) != -1)
ok = 1;
if (file) fclose(file);
return ok;
}
/* signal to pipe delivery implementation */
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
/* pipe private to process */
static int sigpipe[2];
/* create a signal pipe, returns 0 for success, -1 with errno for failure */
int sigpipe_create(void)
{
int rc;
rc = pipe(sigpipe);
if (rc < 0) return rc;
fcntl(sigpipe[0], F_SETFD, FD_CLOEXEC);
fcntl(sigpipe[1], F_SETFD, FD_CLOEXEC);
#ifdef O_NONBLOCK
#define FLAG_TO_SET O_NONBLOCK
#else
#ifdef SYSV
#define FLAG_TO_SET O_NDELAY
#else /* BSD */
#define FLAG_TO_SET FNDELAY
#endif
#endif
rc = fcntl(sigpipe[1], F_GETFL);
if (rc != -1)
rc = fcntl(sigpipe[1], F_SETFL, rc | FLAG_TO_SET);
if (rc < 0) return rc;
return 0;
#undef FLAG_TO_SET
}
/* generic handler for signals, writes signal number to pipe */
void sigpipe_handler(int signum)
{
write(sigpipe[1], &signum, sizeof(signum));
signal(signum, sigpipe_handler);
}
/* assign a signal number to the pipe */
void sigpipe_assign(int signum)
{
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sigpipe_handler;
sigaction(signum, &sa, NULL);
}
/* return the signal pipe read file descriptor for select(2) */
int sigpipe_fd(void)
{
return sigpipe[0];
}
/* read and return the pending signal from the pipe */
int sigpipe_read(void)
{
int signum;
read(sigpipe[0], &signum, sizeof(signum));
return signum;
}
void sigpipe_close(void)
{
close(sigpipe[0]);
close(sigpipe[1]);
}

54
util.h Normal file
View File

@ -0,0 +1,54 @@
/* util.h ....... error message utilities.
* C. Scott Ananian <cananian@alumni.princeton.edu>
*
* $Id: util.h,v 1.8 2011/12/19 07:15:03 quozl Exp $
*/
#ifndef INC_UTIL_H
#define INC_UTIL_H
/* log_string is an identifier for this pptp process, passed from
command line using --log-string=X, and included with every log message.
Useful for people with multiple pptp sessions open at a time */
extern const char * log_string;
/* log_level sets the logging verbosity. Values range from 0 (errors only)
to 1 (errors and warnings) to 2 (high verbosity, for debugging) */
extern int log_level;
void _log(const char *func, const char *file, int line, const char *format, ...)
__attribute__ ((format (printf, 4, 5)));
void _warn(const char *func, const char *file, int line, const char *format, ...)
__attribute__ ((format (printf, 4, 5)));
void _fatal(const char *func, const char *file, int line, const char *format, ...)
__attribute__ ((format (printf, 4, 5))) __attribute__ ((noreturn));
#define log(format, args...) \
_log(__FUNCTION__,__FILE__,__LINE__, format , ## args)
#define warn(format, args...) \
_warn(__FUNCTION__,__FILE__,__LINE__, format , ## args)
#define fatal(format, args...) \
_fatal(__FUNCTION__,__FILE__,__LINE__, format , ## args)
int file2fd(const char *path, const char *mode, int fd);
/* signal to pipe delivery implementation */
/* create a signal pipe, returns 0 for success, -1 with errno for failure */
int sigpipe_create(void);
/* generic handler for signals, writes signal number to pipe */
void sigpipe_handler(int signum);
/* assign a signal number to the pipe */
void sigpipe_assign(int signum);
/* return the signal pipe read file descriptor for select(2) */
int sigpipe_fd(void);
/* read and return the pending signal from the pipe */
int sigpipe_read(void);
void sigpipe_close(void);
#endif /* INC_UTIL_H */

209
vector.c Normal file
View File

@ -0,0 +1,209 @@
/* vector.c ..... store a vector of PPTP_CALL information and search it
* efficiently.
* C. Scott Ananian <cananian@alumni.princeton.edu>
*
* $Id: vector.c,v 1.4 2011/12/19 07:15:03 quozl Exp $
*/
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "pptp_ctrl.h"
#include "vector.h"
/* #define VECTOR_DEBUG */
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
struct vector_item {
int key;
PPTP_CALL *call;
};
struct vector_struct {
struct vector_item *item;
int size;
int alloc;
#ifdef VECTOR_DEBUG
int key_max;
#endif
};
static struct vector_item *binary_search(VECTOR *v, int key);
/*** vector_create ************************************************************/
VECTOR *vector_create(void)
{
const int INITIAL_SIZE = 4;
VECTOR *v = malloc(sizeof(*v));
if (v == NULL) return v;
v->size = 0;
v->alloc = INITIAL_SIZE;
v->item = malloc(sizeof(*(v->item)) * (v->alloc));
#ifdef VECTOR_DEBUG
v->key_max = -1;
#endif
if (v->item == NULL) { free(v); return NULL; }
else return v;
}
/*** vector_destroy ***********************************************************/
void vector_destroy(VECTOR *v)
{
free(v->item);
#ifdef VECTOR_DEBUG
v->item = NULL;
#endif
free(v);
}
/*** vector_size **************************************************************/
int vector_size(VECTOR *v)
{
assert(v != NULL);
return v->size;
}
/*** vector_insert*************************************************************
* nice thing about file descriptors is that we are assured by POSIX
* that they are monotonically increasing.
*/
int vector_insert(VECTOR *v, int key, PPTP_CALL * call)
{
int i;
assert(v != NULL && call != NULL);
assert(!vector_contains(v, key));
#ifdef VECTOR_DEBUG
assert(v->key_max < key);
#endif
if (!(v->size < v->alloc)) {
void *tmp = realloc(v->item, sizeof(*(v->item)) * 2 * v->alloc);
if (tmp != NULL) {
v->alloc *= 2;
v->item = tmp;
} else return FALSE; /* failed to alloc memory. */
}
assert(v->size < v->alloc);
/* for safety, we make this work in the general case;
* but this is optimized for adding call to the end of the vector.
*/
for(i = v->size - 1; i >= 0; i--)
if (v->item[i].key < key)
break;
/* insert after item i */
memmove(&v->item[i + 2], &v->item[i + 1],
(v->size - i - 1) * sizeof(*(v->item)));
v->item[i + 1].key = key;
v->item[i + 1].call = call;
v->size++;
#ifdef VECTOR_DEBUG
if (v->key_max < key) /* ie, always. */
v->key_max = key;
#endif
return TRUE;
}
/*** vector_remove ************************************************************/
int vector_remove(VECTOR *v, int key)
{
struct vector_item *tmp;
assert(v != NULL);
if ((tmp =binary_search(v,key)) == NULL) return FALSE;
assert(tmp >= v->item && tmp < v->item + v->size);
memmove(tmp, tmp + 1, (v->size - (tmp - v->item) - 1) * sizeof(*(v->item)));
v->size--;
return TRUE;
}
/*** vector_search ************************************************************/
int vector_search(VECTOR *v, int key, PPTP_CALL **call)
{
struct vector_item *tmp;
assert(v != NULL);
tmp = binary_search(v, key);
if (tmp ==NULL) return FALSE;
*call = tmp->call;
return TRUE;
}
/*** vector_contains **********************************************************/
int vector_contains(VECTOR *v, int key)
{
assert(v != NULL);
return (binary_search(v, key) != NULL);
}
/*** vector_item **************************************************************/
static struct vector_item *binary_search(VECTOR *v, int key)
{
int l,r,x;
l = 0;
r = v->size - 1;
while (r >= l) {
x = (l + r)/2;
if (key < v->item[x].key) r = x - 1; else l = x + 1;
if (key == v->item[x].key) return &(v->item[x]);
}
return NULL;
}
/*** vector_scan ***************************************************************
* Hmm. Let's be fancy and use a binary search for the first
* unused key, taking advantage of the list is stored sorted; ie
* we can look at pointers and keys at two different locations,
* and if (ptr1 - ptr2) = (key1 - key2) then all the slots
* between ptr1 and ptr2 are filled. Note that ptr1-ptr2 should
* never be greater than key1-key2 (no duplicate keys!)... we
* check for this.
*/
int vector_scan(VECTOR *v, int lo, int hi, int *key)
{
int l,r,x;
assert(v != NULL);
assert(key != NULL);
if ((v->size<1) || (lo < v->item[0].key)) { *key = lo; return TRUE; }
/* our array bounds */
l = 0; r = v->size - 1;
while (r > l) {
/* check for a free spot right after l */
if (v->item[l].key + 1 < v->item[l + 1].key) { /* found it! */
*key = v->item[l].key + 1;
return TRUE;
}
/* no dice. Let's see if the free spot is before or after the midpoint */
x = (l + r)/2;
/* Okay, we have right (r), left (l) and the probe (x). */
assert(x - l <= v->item[x].key - v->item[l].key);
assert(r - x <= v->item[r].key - v->item[x].key);
if (x - l < v->item[x].key - v->item[l].key)
/* room between l and x */
r = x;
else /* no room between l and x */
if (r - x < v->item[r].key - v->item[x].key)
/* room between x and r */
l = x;
else /* no room between x and r, either */
break; /* game over, man. */
}
/* no room found in already allocated space. Check to see if
* there's free space above allocated entries. */
if (v->item[v->size - 1].key < hi) {
*key = v->item[v->size - 1].key + 1;
return TRUE;
}
/* outta luck */
return FALSE;
}
/*** vector_get_Nth ***********************************************************/
PPTP_CALL * vector_get_Nth(VECTOR *v, int n)
{
assert(v != NULL);
assert(0 <= n && n < vector_size(v));
return v->item[n].call;
}

31
vector.h Normal file
View File

@ -0,0 +1,31 @@
/* vector.h ..... store a vector of PPTP_CALL information and search it
* efficiently.
* C. Scott Ananian <cananian@alumni.princeton.edu>
*
* $Id: vector.h,v 1.2 2011/12/19 07:15:03 quozl Exp $
*/
#ifndef INC_VECTOR_H
#define INC_VECTOR_H
#include "pptp_ctrl.h" /* for definition of PPTP_CALL */
typedef struct vector_struct VECTOR;
VECTOR *vector_create(void);
void vector_destroy(VECTOR *v);
int vector_size(VECTOR *v);
/* vector_insert and vector_search return TRUE on success, FALSE on failure. */
int vector_insert(VECTOR *v, int key, PPTP_CALL * call);
int vector_remove(VECTOR *v, int key);
int vector_search(VECTOR *v, int key, PPTP_CALL ** call);
/* vector_contains returns FALSE if not found, TRUE if found. */
int vector_contains(VECTOR *v, int key);
/* find first unused key. Returns TRUE on success, FALSE if no. */
int vector_scan(VECTOR *v, int lo, int hi, int *key);
/* get a specific PPTP_CALL ... useful only when iterating. */
PPTP_CALL * vector_get_Nth(VECTOR *v, int n);
#endif /* INC_VECTOR_H */

99
vector_test.c Normal file
View File

@ -0,0 +1,99 @@
/* vector_test.c .... Test the vector package.
* C. Scott Ananian <cananian@alumni.princeton.edu>
*
* $Id: vector_test.c,v 1.2 2003/06/17 17:25:47 reink Exp $
*/
#include <stdlib.h>
#include <assert.h>
#include "vector.h"
#define MAX 25
void main(void) {
int i, j, *d, retval;
VECTOR *v = vector_create();
assert(v != NULL);
assert(vector_size(v)==0);
for (i=0; i<=MAX; i++) {
assert(!vector_contains(v, i));
assert(!vector_remove(v, i));
assert(!vector_search(v, i, (PPTP_CALL **)&j));
retval = vector_scan(v, i, MAX*2, &j);
assert(retval);
assert(j==i);
}
for (i=1; i<=MAX; i++) {
d = malloc(sizeof(int));
*d = i;
retval = vector_insert(v, i, (PPTP_CALL *)d);
assert(retval);
assert(vector_size(v)==i);
}
for (i=1; i<MAX; i++) {
retval = vector_search(v, i, (PPTP_CALL **)&d);
assert(retval);
assert(*d==i);
retval = vector_contains(v, i);
assert(retval);
}
assert(vector_size(v)==MAX);
retval = vector_contains(v, MAX+1);
assert(!retval);
retval = vector_search(v, MAX+1, (PPTP_CALL **)&j);
assert(!retval);
retval = vector_scan(v, 0, MAX, &j);
assert(retval);
assert(j==0);
retval = vector_scan(v, 1, MAX, &j);
assert(!retval);
retval = vector_scan(v, 1, MAX+1, &j);
assert(retval);
assert(j==MAX+1);
retval = vector_scan(v, 1, MAX+MAX, &j);
assert(retval);
assert(j==MAX+1);
for (i=0; i<(MAX*10); i++) {
int k = (random() % MAX) + 1;
assert(vector_contains(v, k));
assert(!vector_scan(v, 1, k, &j));
assert(!vector_scan(v, k, MAX, &j));
retval = vector_remove(v, k);
assert(retval);
assert(vector_size(v)==MAX-1);
assert(!vector_contains(v, k));
assert(!vector_search(v, k, (PPTP_CALL **) &j));
retval = vector_scan(v, 1, MAX, &j);
assert(retval);
assert(j==k);
d = malloc(sizeof(int));
*d = k;
retval = vector_insert(v, k, (PPTP_CALL *) d);
assert(retval);
assert(vector_size(v)==MAX);
assert(vector_contains(v, k));
assert(!vector_scan(v, 1, MAX, &j));
retval = vector_search(v, k, (PPTP_CALL **) &d);
assert(retval);
assert(*d==k);
}
for (i=1; i<=MAX; i++) {
assert(vector_size(v)==MAX-(i-1));
vector_remove(v, i);
assert(vector_size(v)==MAX-i);
assert(!vector_contains(v, i));
retval = vector_search(v, i, (PPTP_CALL **) &j);
assert(!retval);
retval = vector_scan(v, 1, MAX, &j);
assert(retval);
assert(j==1);
}
assert(vector_size(v)==0);
vector_destroy(v);
exit(0);
}

8
version.c Normal file
View File

@ -0,0 +1,8 @@
/* version.c ..... keep track of package version number.
* C. Scott Ananian <cananian@alumni.princeton.edu>
*
* $Id: version.c,v 1.3 2004/06/22 09:52:26 quozl Exp $
*/
#include "config.h"
const char * version = "pptp version " PPTP_LINUX_VERSION;

10
version.h Normal file
View File

@ -0,0 +1,10 @@
/* version.h ..... keep track of package version number.
* C. Scott Ananian <cananian@alumni.princeton.edu>
*
* $Id: version.h,v 1.1 2000/12/23 08:19:51 scott Exp $
*/
#ifndef INC_VERSION_H
#define INC_VERSION_H
extern const char * version;
#endif /* INC_VERSION_H */