summaryrefslogtreecommitdiff
path: root/src/pppoe-sniff.c (plain)
blob: 156985752ac044da6ac469cf40ab99b3215d78a3
1/***********************************************************************
2*
3* pppoe-sniff.c
4*
5* Sniff a network for likely-looking PPPoE frames and deduce the value
6* to supply to PPPOE_EXTRA in /etc/ppp/pppoe.conf. USE AT YOUR OWN RISK.
7*
8* Copyright (C) 2000 by Roaring Penguin Software Inc.
9*
10* This program may be distributed according to the terms of the GNU
11* General Public License, version 2 or (at your option) any later version.
12*
13* LIC: GPL
14*
15***********************************************************************/
16
17static char const RCSID[] =
18"$Id$";
19
20#include "pppoe.h"
21
22#ifdef HAVE_GETOPT_H
23#include <getopt.h>
24#endif
25
26#include <errno.h>
27#include <unistd.h>
28#include <string.h>
29#include <stdlib.h>
30
31#ifdef USE_DLPI
32#include <sys/dlpi.h>
33/* function declarations */
34void dlpromisconreq( int fd, u_long level);
35void dlokack(int fd, char *bufp);
36#endif
37
38/* Default interface if no -I option given */
39#define DEFAULT_IF "eth0"
40
41/* Global vars */
42int SeenPADR = 0;
43int SeenSess = 0;
44UINT16_t SessType, DiscType;
45
46char *IfName = NULL; /* Interface name */
47char *ServiceName = NULL; /* Service name */
48
49/**********************************************************************
50*%FUNCTION: parsePADRTags
51*%ARGUMENTS:
52* type -- tag type
53* len -- tag length
54* data -- tag data
55* extra -- extra user data.
56*%RETURNS:
57* Nothing
58*%DESCRIPTION:
59* Picks interesting tags out of a PADR packet
60***********************************************************************/
61void
62parsePADRTags(UINT16_t type, UINT16_t len, unsigned char *data,
63 void *extra)
64{
65 switch(type) {
66 case TAG_SERVICE_NAME:
67 ServiceName = malloc(len+1);
68 if (ServiceName) {
69 memcpy(ServiceName, data, len);
70 ServiceName[len] = 0;
71 }
72 break;
73 }
74}
75
76/**********************************************************************
77*%FUNCTION: fatalSys
78*%ARGUMENTS:
79* str -- error message
80*%RETURNS:
81* Nothing
82*%DESCRIPTION:
83* Prints a message plus the errno value to stderr and exits.
84***********************************************************************/
85void
86fatalSys(char const *str)
87{
88 char buf[1024];
89 sprintf(buf, "%.256s: %.256s", str, strerror(errno));
90 printErr(buf);
91 exit(1);
92}
93
94/**********************************************************************
95*%FUNCTION: rp_fatal
96*%ARGUMENTS:
97* str -- error message
98*%RETURNS:
99* Nothing
100*%DESCRIPTION:
101* Prints a message to stderr and syslog and exits.
102***********************************************************************/
103void
104rp_fatal(char const *str)
105{
106 printErr(str);
107 exit(1);
108}
109
110/**********************************************************************
111*%FUNCTION: usage
112*%ARGUMENTS:
113* argv0 -- program name
114*%RETURNS:
115* Nothing
116*%DESCRIPTION:
117* Prints usage information and exits.
118***********************************************************************/
119void
120usage(char const *argv0)
121{
122 fprintf(stderr, "Usage: %s [options]\n", argv0);
123 fprintf(stderr, "Options:\n");
124 fprintf(stderr, " -I if_name -- Specify interface (default %s.)\n",
125 DEFAULT_IF);
126 fprintf(stderr, " -V -- Print version and exit.\n");
127 fprintf(stderr, "\nPPPoE Version %s, Copyright (C) 2000 Roaring Penguin Software Inc.\n", VERSION);
128 fprintf(stderr, "PPPoE comes with ABSOLUTELY NO WARRANTY.\n");
129 fprintf(stderr, "This is free software, and you are welcome to redistribute it under the terms\n");
130 fprintf(stderr, "of the GNU General Public License, version 2 or any later version.\n");
131 fprintf(stderr, "http://www.roaringpenguin.com\n");
132 exit(0);
133}
134
135#if !defined(USE_LINUX_PACKET) && !defined(USE_DLPI)
136
137int
138main()
139{
140 fprintf(stderr, "Sorry, pppoe-sniff works only on Linux.\n");
141 return 1;
142}
143
144#else
145
146/**********************************************************************
147*%FUNCTION: main
148*%ARGUMENTS:
149* argc, argv -- count and values of command-line arguments
150*%RETURNS:
151* Nothing
152*%DESCRIPTION:
153* Main program
154***********************************************************************/
155int
156main(int argc, char *argv[])
157{
158 int opt;
159 int sock;
160 PPPoEPacket pkt;
161 int size;
162#ifdef USE_DLPI
163 long buf[MAXDLBUF];
164#endif
165
166 if (getuid() != geteuid() ||
167 getgid() != getegid()) {
168 fprintf(stderr, "SECURITY WARNING: pppoe-sniff will NOT run suid or sgid. Fix your installation.\n");
169 exit(1);
170 }
171
172 while((opt = getopt(argc, argv, "I:V")) != -1) {
173 switch(opt) {
174 case 'I':
175 SET_STRING(IfName, optarg);
176 break;
177 case 'V':
178 printf("pppoe-sniff: Roaring Penguin PPPoE Version %s\n", VERSION);
179 exit(0);
180 default:
181 usage(argv[0]);
182 }
183 }
184
185 /* Pick a default interface name */
186 if (!IfName) {
187 IfName = DEFAULT_IF;
188 }
189
190 /* Open the interface */
191#ifdef USE_DLPI
192 sock = openInterface(IfName, Eth_PPPOE_Discovery, NULL);
193 dlpromisconreq(sock, DL_PROMISC_PHYS);
194 dlokack(sock, (char *)buf);
195 dlpromisconreq(sock, DL_PROMISC_SAP);
196 dlokack(sock, (char *)buf);
197#else
198
199 sock = openInterface(IfName, ETH_P_ALL, NULL);
200
201#endif
202
203 /* We assume interface is in promiscuous mode -- use ifconfig to
204 ensure this */
205 fprintf(stderr, "Sniffing for PADR. Start your connection on another machine...\n");
206 while (!SeenPADR) {
207 if (receivePacket(sock, &pkt, &size) < 0) continue;
208 if (ntohs(pkt.length) + HDR_SIZE > (unsigned int)size) continue;
209 if (pkt.ver != 1 || pkt.type != 1) continue;
210 if (pkt.code != CODE_PADR) continue;
211
212 /* Looks promising... parse it */
213 if (parsePacket(&pkt, parsePADRTags, NULL) < 0) {
214 continue;
215 }
216 DiscType = ntohs(pkt.ethHdr.h_proto);
217 fprintf(stderr, "\nExcellent! Sniffed a likely-looking PADR.\n");
218 break;
219 }
220
221 while (!SeenSess) {
222 if (receivePacket(sock, &pkt, &size) < 0) continue;
223 if (ntohs(pkt.length) + HDR_SIZE > (unsigned int)size) continue;
224 if (pkt.ver != 1 || pkt.type != 1) continue;
225 if (pkt.code != CODE_SESS) continue;
226
227 /* Cool! */
228 SessType = ntohs(pkt.ethHdr.h_proto);
229 break;
230 }
231
232 fprintf(stderr, "Wonderful! Sniffed a likely-looking session packet.\n");
233 if ((ServiceName == NULL || *ServiceName == 0) &&
234 DiscType == ETH_PPPOE_DISCOVERY &&
235 SessType == ETH_PPPOE_SESSION) {
236 fprintf(stderr, "\nGreat! It looks like a standard PPPoE service.\nYou should not need anything special in the configuration file.\n");
237 return 0;
238 }
239
240 fprintf(stderr, "\nOK, looks like you need something special in the configuration file.\nTry this:\n\n");
241 if (ServiceName != NULL && *ServiceName != 0) {
242 fprintf(stderr, "SERVICENAME='%s'\n", ServiceName);
243 }
244 if (DiscType != ETH_PPPOE_DISCOVERY || SessType != ETH_PPPOE_SESSION) {
245 fprintf(stderr, " PPPOE_EXTRA='-f %x:%x'\n", DiscType, SessType);
246 }
247 return 0;
248}
249
250#endif
251/**********************************************************************
252*%FUNCTION: sysErr
253*%ARGUMENTS:
254* str -- error message
255*%RETURNS:
256* Nothing
257*%DESCRIPTION:
258* Prints a message plus the errno value to syslog.
259***********************************************************************/
260void
261sysErr(char const *str)
262{
263 char buf[1024];
264 sprintf(buf, "%.256s: %.256s", str, strerror(errno));
265 printErr(buf);
266}
267