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 | |
17 | static 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 */ |
34 | void dlpromisconreq( int fd, u_long level); |
35 | void 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 */ |
42 | int SeenPADR = 0; |
43 | int SeenSess = 0; |
44 | UINT16_t SessType, DiscType; |
45 | |
46 | char *IfName = NULL; /* Interface name */ |
47 | char *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 | ***********************************************************************/ |
61 | void |
62 | parsePADRTags(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 | ***********************************************************************/ |
85 | void |
86 | fatalSys(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 | ***********************************************************************/ |
103 | void |
104 | rp_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 | ***********************************************************************/ |
119 | void |
120 | usage(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 | |
137 | int |
138 | main() |
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 | ***********************************************************************/ |
155 | int |
156 | main(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 | ***********************************************************************/ |
260 | void |
261 | sysErr(char const *str) |
262 | { |
263 | char buf[1024]; |
264 | sprintf(buf, "%.256s: %.256s", str, strerror(errno)); |
265 | printErr(buf); |
266 | } |
267 |