• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/accel-pptpd/pppd_plugin/src/
1/***************************************************************************
2 *   Copyright (C) 2006 by Kozlov D.   *
3 *   xeb@mail.ru   *
4 *                                                                         *
5 *   This program is free software; you can redistribute it and/or modify  *
6 *   it under the terms of the GNU General Public License as published by  *
7 *   the Free Software Foundation; either version 2 of the License, or     *
8 *   (at your option) any later version.                                   *
9 *                                                                         *
10 *   This program is distributed in the hope that it will be useful,       *
11 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13 *   GNU General Public License for more details.                          *
14 *                                                                         *
15 *   You should have received a copy of the GNU General Public License     *
16 *   along with this program; if not, write to the                         *
17 *   Free Software Foundation, Inc.,                                       *
18 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19 ***************************************************************************/
20
21
22#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
25
26#include <netinet/in.h>
27#include <arpa/inet.h>
28#include <sys/un.h>
29#include <netdb.h>
30#include <stdio.h>
31#include <string.h>
32#include <stdlib.h>
33#include <syslog.h>
34#include <unistd.h>
35#include <signal.h>
36#include <errno.h>
37#include <fcntl.h>
38#include <sys/wait.h>
39#include <sys/ioctl.h>
40
41#include "pppd/pppd.h"
42#include "pppd/fsm.h"
43#include "pppd/lcp.h"
44#include "pppd/ipcp.h"
45#include "pppd/ccp.h"
46#include "pppd/pathnames.h"
47
48#include "pptp_callmgr.h"
49#include <net/if.h>
50#include <net/ethernet.h>
51//#include "if_pppox.h" //Yau del
52#include <linux/if_pppox.h>
53
54#include <stdio.h>
55#include <stdlib.h>
56
57
58
59extern char** environ;
60
61char pppd_version[] = PPPD_VERSION;
62extern int new_style_driver;
63
64
65char *pptp_server = NULL;
66char *pptp_client = NULL;
67char *pptp_phone = NULL;
68int pptp_sock=-1;
69int pptp_timeout=100000;
70struct in_addr localbind = { INADDR_NONE };
71
72static int callmgr_sock;
73static int pptp_fd;
74int call_ID;
75
76//static struct in_addr get_ip_address(char *name);
77static int open_callmgr(int call_id,struct in_addr inetaddr, char *phonenr,int window);
78static void launch_callmgr(int call_is,struct in_addr inetaddr, char *phonenr,int window);
79static int get_call_id(int sock, pid_t gre, pid_t pppd, u_int16_t *peer_call_id);
80
81//static int pptp_devname_hook(char *cmd, char **argv, int doit);
82static option_t Options[] =
83{
84    { "pptp_server", o_string, &pptp_server,
85      "PPTP Server" },
86    { "pptp_client", o_string, &pptp_client,
87      "PPTP Client" },
88    { "pptp_sock",o_int, &pptp_sock,
89      "PPTP socket" },
90    { "pptp_phone", o_string, &pptp_phone,
91      "PPTP Phone number" },
92    { NULL }
93};
94
95static int pptp_connect(void);
96//static void pptp_send_config(int mtu,u_int32_t asyncmap,int pcomp,int accomp);
97//static void pptp_recv_config(int mru,u_int32_t asyncmap,int pcomp,int accomp);
98static void pptp_disconnect(void);
99
100struct channel pptp_channel = {
101    options: Options,
102    //process_extra_options: &PPPOEDeviceOptions,
103    check_options: NULL,
104    connect: &pptp_connect,
105    disconnect: &pptp_disconnect,
106    establish_ppp: &generic_establish_ppp,
107    disestablish_ppp: &generic_disestablish_ppp,
108    //send_config: &pptp_send_config,
109    //recv_config: &pptp_recv_config,
110    close: NULL,
111    cleanup: NULL
112};
113
114static int pptp_start_server(void)
115{
116	pptp_fd=pptp_sock;
117	sprintf(ppp_devnam,"pptp (%s)",pptp_client);
118
119	return pptp_fd;
120}
121static int pptp_start_client(void)
122{
123	socklen_t len;
124	struct sockaddr_pppox src_addr,dst_addr;
125	struct hostent *hostinfo;
126
127	hostinfo=gethostbyname(pptp_server);
128  if (!hostinfo)
129	{
130		error("PPTP: Unknown host %s\n", pptp_server);
131		return -1;
132	}
133	dst_addr.sa_addr.pptp.sin_addr=*(struct in_addr*)hostinfo->h_addr;
134	{
135		int sock;
136		struct sockaddr_in addr;
137		len=sizeof(addr);
138		addr.sin_addr=dst_addr.sa_addr.pptp.sin_addr;
139		addr.sin_family=AF_INET;
140		addr.sin_port=htons(1700);
141		sock=socket(AF_INET,SOCK_DGRAM,0);
142		if (connect(sock,(struct sockaddr*)&addr,sizeof(addr)))
143		{
144			close(sock);
145			error("PPTP: connect failed (%s)\n",strerror(errno));
146			return -1;
147		}
148		getsockname(sock,(struct sockaddr*)&addr,&len);
149		src_addr.sa_addr.pptp.sin_addr=addr.sin_addr;
150		close(sock);
151	}
152	//info("PPTP: connect server=%s\n",inet_ntoa(conn.sin_addr));
153	//conn.loc_addr.s_addr=INADDR_NONE;
154	//conn.timeout=1;
155	//conn.window=pptp_window;
156
157	src_addr.sa_family=AF_PPPOX;
158	src_addr.sa_protocol=PX_PROTO_PPTP;
159	src_addr.sa_addr.pptp.call_id=0;
160
161	dst_addr.sa_family=AF_PPPOX;
162	dst_addr.sa_protocol=PX_PROTO_PPTP;
163	dst_addr.sa_addr.pptp.call_id=0;
164
165	pptp_fd=socket(AF_PPPOX,SOCK_STREAM,PX_PROTO_PPTP);
166	if (pptp_fd<0)
167	{
168		error("PPTP: failed to create PPTP socket (%s)\n",strerror(errno));
169		return -1;
170	}
171	if (bind(pptp_fd,(struct sockaddr*)&src_addr,sizeof(src_addr)))
172	{
173		close(pptp_fd);
174		error("PPTP: failed to bind PPTP socket (%s)\n",strerror(errno));
175		return -1;
176	}
177	len=sizeof(src_addr);
178	getsockname(pptp_fd,(struct sockaddr*)&src_addr,&len);
179	call_ID=src_addr.sa_addr.pptp.call_id;
180
181  do {
182        /*
183         * Open connection to call manager (Launch call manager if necessary.)
184         */
185        callmgr_sock = open_callmgr(src_addr.sa_addr.pptp.call_id,dst_addr.sa_addr.pptp.sin_addr, pptp_phone,50);
186	if (callmgr_sock<0)
187	{
188		close(pptp_fd);
189		return -1;
190        }
191        /* Exchange PIDs, get call ID */
192    } while (get_call_id(callmgr_sock, getpid(), getpid(), &dst_addr.sa_addr.pptp.call_id) < 0);
193
194	if (connect(pptp_fd,(struct sockaddr*)&dst_addr,sizeof(dst_addr)))
195	{
196		close(callmgr_sock);
197		close(pptp_fd);
198		error("PPTP: failed to connect PPTP socket (%s)\n",strerror(errno));
199		return -1;
200	}
201
202	sprintf(ppp_devnam,"pptp (%s)",pptp_server);
203
204	return pptp_fd;
205}
206static int pptp_connect(void)
207{
208	if ((!pptp_server && !pptp_client) || (pptp_server && pptp_client))
209	{
210		fatal("PPTP: unknown mode (you must specify pptp_server or pptp_client option)");
211		return -1;
212	}
213
214	if (pptp_server) return pptp_start_client();
215	return pptp_start_server();
216}
217
218static void pptp_disconnect(void)
219{
220	if (pptp_server) close(callmgr_sock);
221	close(pptp_fd);
222}
223
224static int open_callmgr(int call_id,struct in_addr inetaddr, char *phonenr,int window)
225{
226    /* Try to open unix domain socket to call manager. */
227    struct sockaddr_un where;
228    const int NUM_TRIES = 3;
229    int i, fd;
230    pid_t pid;
231    int status;
232    /* Open socket */
233    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
234    {
235        fatal("Could not create unix domain socket: %s", strerror(errno));
236    }
237    /* Make address */
238    callmgr_name_unixsock(&where, inetaddr, localbind);
239    for (i = 0; i < NUM_TRIES; i++)
240    {
241        if (connect(fd, (struct sockaddr *) &where, sizeof(where)) < 0)
242        {
243            /* couldn't connect.  We'll have to launch this guy. */
244
245            unlink (where.sun_path);
246
247            /* fork and launch call manager process */
248            switch (pid = fork())
249            {
250                case -1: /* failure */
251                    fatal("fork() to launch call manager failed.");
252                case 0: /* child */
253                {
254                    close (fd);
255                    close(pptp_fd);
256                    /* close the pty and gre in the call manager */
257                   // close(pty_fd);
258                    //close(gre_fd);
259                    launch_callmgr(call_id,inetaddr, phonenr,window);
260                }
261                default: /* parent */
262                    waitpid(pid, &status, 0);
263                    if (status!= 0)
264		    {
265			close(fd);
266			error("Call manager exited with error %d", status);
267			return -1;
268		    }
269                    break;
270            }
271            sleep(1);
272        }
273        else return fd;
274    }
275    close(fd);
276    error("Could not launch call manager after %d tries.", i);
277    return -1;   /* make gcc happy */
278}
279
280/*** call the call manager main ***********************************************/
281static void launch_callmgr(int call_id,struct in_addr inetaddr, char *phonenr,int window)
282{
283			char win[10];
284			char call[10];
285      char *my_argv[9] = { "pptp", inet_ntoa(inetaddr), "--call_id",call,"--phone",phonenr,"--window",win,NULL };
286      char buf[128];
287      sprintf(win,"%u",window);
288      sprintf(call,"%u",call_id);
289      snprintf(buf, sizeof(buf), "pptp: call manager for %s", my_argv[1]);
290      //inststr(argc, argv, envp, buf);
291      exit(callmgr_main(8, my_argv, environ));
292}
293
294/*** exchange data with the call manager  *************************************/
295/* XXX need better error checking XXX */
296static int get_call_id(int sock, pid_t gre, pid_t pppd,
297		u_int16_t *peer_call_id)
298{
299    u_int16_t m_call_id, m_peer_call_id;
300    /* write pid's to socket */
301    /* don't bother with network byte order, because pid's are meaningless
302     * outside the local host.
303     */
304    int rc;
305    rc = write(sock, &gre, sizeof(gre));
306    if (rc != sizeof(gre))
307        return -1;
308    rc = write(sock, &pppd, sizeof(pppd));
309    if (rc != sizeof(pppd))
310        return -1;
311    rc = read(sock,  &m_call_id, sizeof(m_call_id));
312    if (rc != sizeof(m_call_id))
313        return -1;
314    rc = read(sock,  &m_peer_call_id, sizeof(m_peer_call_id));
315    if (rc != sizeof(m_peer_call_id))
316        return -1;
317    /*
318     * XXX FIXME ... DO ERROR CHECKING & TIME-OUTS XXX
319     * (Rhialto: I am assuming for now that timeouts are not relevant
320     * here, because the read and write calls would return -1 (fail) when
321     * the peer goes away during the process. We know it is (or was)
322     * running because the connect() call succeeded.)
323     * (James: on the other hand, if the route to the peer goes away, we
324     * wouldn't get told by read() or write() for quite some time.)
325     */
326    *peer_call_id = m_peer_call_id;
327    return 0;
328}
329
330void plugin_init(void)
331{
332    /*if (!ppp_available() && !new_style_driver)
333    {
334				fatal("Linux kernel does not support PPP -- are you running 2.4.x?");
335    }*/
336
337    add_options(Options);
338
339    info("PPTP plugin version %s compiled for pppd-%s, linux-%s",
340	 VERSION, PPPD_VERSION,KERNELVERSION);
341
342    the_channel = &pptp_channel;
343    modem = 0;
344}
345
346