]> git.vomp.tv Git - vompserver.git/blob - bootpd.c
Bootp server
[vompserver.git] / bootpd.c
1 /*
2     Copyright 2006 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "bootpd.h"
22
23 //void dump(unsigned char* data, USHORT size);
24 //unsigned char dcc(UCHAR c);
25
26 Bootpd::Bootpd()
27 {
28   log = Log::getInstance();
29 }
30
31 Bootpd::~Bootpd()
32 {
33   shutdown();
34 }
35
36 int Bootpd::shutdown()
37 {
38   if (threadIsActive()) threadCancel();
39   ds.shutdown();
40
41   return 1;
42 }
43
44 int Bootpd::run()
45 {
46   if (threadIsActive()) return 1;
47   log->log("BOOTPD", Log::DEBUG, "Starting bootpd");
48
49   if (!ds.init(16867))
50   {
51     log->log("BOOTPD", Log::DEBUG, "DSock init error");
52     shutdown();
53     return 0;
54   }
55
56   if (!threadStart())
57   {
58     log->log("BOOTPD", Log::DEBUG, "Thread start error");
59     shutdown();
60     return 0;
61   }
62
63   log->log("BOOTPD", Log::DEBUG, "Bootp replier started");
64   return 1;
65 }
66
67 void Bootpd::threadMethod()
68 {
69   int retval;
70   while(1)
71   {
72     log->log("BOOTPD", Log::DEBUG, "Starting wait");
73     retval = ds.waitforMessage(0);
74     log->log("BOOTPD", Log::DEBUG, "Wait finished");
75
76     if (retval == 0)
77     {
78       log->log("BOOTPD", Log::CRIT, "Wait for packet error");
79       return;
80     }
81     else if (retval == 1)
82     {
83       continue;
84     }
85     else
86     {
87       processRequest((UCHAR*)ds.getData(), ds.getDataLength());
88     }
89   }
90 }
91
92 void Bootpd::processRequest(UCHAR* data, int length)
93 {
94   log->log("BOOTPD", Log::DEBUG, "Got request");
95 //  dump(data, (USHORT)length);
96
97   if (data[0] != 1) return;  // Check it's a request
98
99
100   // Open a config file for the given MAC
101
102   const char* configDir = cPlugin::ConfigDirectory();
103 //  char* configDir = "/opt/dvb/vdr-config-1.3/plugins";
104   if (!configDir)
105   {
106     log->log("BOOTPD", Log::ERR, "No config dir!");
107     return;
108   }
109
110   Config config;
111   char configFileName[PATH_MAX];
112   snprintf(configFileName, PATH_MAX, "%s/vomp-%02X-%02X-%02X-%02X-%02X-%02X.conf", configDir, data[28], data[29], data[30], data[31], data[32], data[33]);
113   if (config.init(configFileName))
114   {
115     log->log("BOOTPD", Log::DEBUG, "Opened config file: %s", configFileName);
116   }
117   else
118   {
119     log->log("BOOTPD", Log::ERR, "Could not open/create config file: %s", configFileName);
120     return;
121   }
122
123   // Get an IP for the MVP (make a local copy so future returns don't all have to free string)
124   char newClientIP[100];
125   newClientIP[0] = '\0';
126   bool configHasIP = false;
127   char* cfnewClientIP = config.getValueString("Boot", "IP");
128   if (cfnewClientIP)
129   {
130     strncpy(newClientIP, cfnewClientIP, 99);
131     delete[] cfnewClientIP;
132     configHasIP = true;
133
134     log->log("BOOTPD", Log::DEBUG, "Found IP %s for MVP", newClientIP);
135   }
136   else
137   {
138     log->log("BOOTPD", Log::WARN, "No IP found for MVP. Hopefully it has one already...");
139   }
140
141   // See if we should enforce the IP from the config file
142   int failure;
143   long enforceConfigIP = config.getValueLong("Boot", "Override IP", &failure);
144   if (newClientIP && enforceConfigIP)
145   {
146     log->log("BOOTPD", Log::DEBUG, "Will enforce IP %s on MVP even if it already has another", newClientIP);
147   }
148   else
149   {
150     log->log("BOOTPD", Log::DEBUG, "Will not change MVP IP if it already has one");
151   }
152
153   // See if the MVP already has an IP
154   bool clientAlreadyHasIP = (data[12] || data[13] || data[14] || data[15]);
155
156   /*
157   Subset of Bootp protocol for MVP
158
159   Incoming fields:
160
161   Opcode                    0              Check for value 1            Set to value 2
162   Hardware type             1
163   Hardware address length   2
164   Hop count                 3
165   Transaction ID            4-7
166   Num seconds               8-9
167   Flags                     10-11
168   Client IP                 12-15
169   Your IP                   16-19                                       Set to MVP IP
170   Server IP                 20-23                                       Set to server IP
171   Gateway IP                24-27
172   Client HW address         28-43  (16)    Use to lookup IP for MVP
173   Server Host Name          44-107 (64)
174   Boot filename             108-235 (128)                               Fill with filename for TFTP
175   Vendor info               236-299 (64)
176
177   IP Possibilities
178
179   mvpAlreadyHasIP    configHasIP    enforceConfigIP    result
180 1 Y        0                0                0             discard
181 2 Y        0                0                1             discard
182 3 Y        0                1                0             set config ip
183 4 Y        0                1                1             set config ip
184 5 Y        1                0                0             set mvp ip
185 6 Y        1                0                1             set enforce false, set mvp ip
186 7 Y        1                1                0             set mvp ip
187 8 Y        1                1                1             set config ip
188   */
189
190   if (!clientAlreadyHasIP && !configHasIP) // cases 1 & 2
191   {
192     log->log("BOOTPD", Log::DEBUG, "No IP found to give to MVP");
193     return;
194   }
195
196   if (!configHasIP) enforceConfigIP = 0;             // case 6
197
198   // Ok, we will send a reply
199
200   in_addr_t finalMVPIP;
201
202   if ((!clientAlreadyHasIP) || (configHasIP && enforceConfigIP))
203   {
204     // Cases 3 & 4,              case 8
205     log->log("BOOTPD", Log::DEBUG, "Giving MVP IP from config");
206     // Set config ip
207     *((in_addr_t*)&data[16]) = inet_addr(newClientIP);
208     finalMVPIP = *((in_addr_t*)&data[16]);
209   }
210   else
211   {
212     // Cases 5 & 7
213     // copy existing ciaddr to yiaddr?
214     log->log("BOOTPD", Log::DEBUG, "Leave YI=0 as MVP already has good IP");
215     finalMVPIP = *((in_addr_t*)&data[12]);
216   }
217
218   // Set Server IP in packet
219   if (!getmyip(finalMVPIP, (in_addr_t*)&data[20]))
220   {
221     log->log("BOOTPD", Log::ERR, "Get my IP failed");
222   }
223
224   // Set filename
225   strncpy((char*)&data[108], "/mvp/vomp-dongle", 127);
226
227   // set to reply
228   data[0] = 2;
229
230 //  dump(data, (USHORT)length);
231
232   ds.send("255.255.255.255", 16868, (char*)data, length);
233 }
234
235
236 int Bootpd::getmyip(in_addr_t destination, in_addr_t* result)
237 {
238   int sockfd, r1, r2;
239   struct sockaddr_in my_addr;
240   struct sockaddr_in dest_addr;
241   socklen_t my_addr_len = sizeof(struct sockaddr_in);
242
243   sockfd = socket(AF_INET, SOCK_DGRAM, 0);
244   if (sockfd == -1) return 0;
245
246   dest_addr.sin_family = AF_INET;
247   dest_addr.sin_port = htons(1);
248   dest_addr.sin_addr.s_addr = destination;
249   memset(&(dest_addr.sin_zero), 0, 8);
250
251   r1 = connect(sockfd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr));
252   if (r1 == -1)
253   {
254     close(sockfd);
255     return 0;
256   }
257
258   memset(&my_addr, 0, sizeof(struct sockaddr_in));
259   r2 = getsockname(sockfd, (struct sockaddr *)&my_addr, &my_addr_len);
260
261   close(sockfd);
262
263   if (r2 == -1) return 0;
264
265   *result = my_addr.sin_addr.s_addr;
266   return 1;
267 }
268
269 /*
270 void dump(unsigned char* data, USHORT size)
271 {
272   printf("Size = %u\n", size);
273
274   USHORT c = 0;
275   while(c < size)
276   {
277     if ((size - c) > 15)
278     {
279       printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X  %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
280         data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
281         data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], data[c+15],
282         dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
283         dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]), dcc(data[c+14]), dcc(data[c+15]));
284       c += 16;
285     }
286     else
287     {
288       switch (size - c)
289       {
290         case 15:
291           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X     %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
292             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
293             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14],
294             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
295             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]), dcc(data[c+14]));
296           c += 15;
297           break;
298         case 14:
299           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X        %c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
300             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
301             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13],
302             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
303             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]));
304           c += 14;
305           break;
306         case 13:
307           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X  %02X           %c%c%c%c%c%c%c%c%c%c%c%c%c\n",
308             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
309             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12],
310             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
311             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]));
312           c += 13;
313           break;
314         case 12:
315           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X %02X               %c%c%c%c%c%c%c%c%c%c%c%c\n",
316             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
317             data[c+8], data[c+9], data[c+10], data[c+11],
318             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
319             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]));
320           c += 12;
321           break;
322         case 11:
323           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X                  %c%c%c%c%c%c%c%c%c%c%c\n",
324             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
325             data[c+8], data[c+9], data[c+10],
326             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
327             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]));
328           c += 11;
329           break;
330         case 10:
331           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X                     %c%c%c%c%c%c%c%c%c%c\n",
332             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
333             data[c+8], data[c+9],
334             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
335             dcc(data[c+8]), dcc(data[c+9]));
336           c += 10;
337           break;
338         case 9:
339           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X                        %c%c%c%c%c%c%c%c%c\n",
340             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
341             data[c+8],
342             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]),
343             dcc(data[c+8]));
344           c += 9;
345           break;
346         case 8:
347           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X                            %c%c%c%c%c%c%c%c\n",
348             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
349             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]));
350           c += 8;
351           break;
352         case 7:
353           printf(" %02X %02X %02X %02X  %02X %02X %02X                               %c%c%c%c%c%c%c\n",
354             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6],
355             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]));
356           c += 7;
357           break;
358         case 6:
359           printf(" %02X %02X %02X %02X  %02X %02X                                  %c%c%c%c%c%c\n",
360             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5],
361             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]));
362           c += 6;
363           break;
364         case 5:
365           printf(" %02X %02X %02X %02X  %02X                                     %c%c%c%c%c\n",
366             data[c], data[c+1], data[c+2], data[c+3], data[c+4],
367             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]));
368           c += 5;
369           break;
370         case 4:
371           printf(" %02X %02X %02X %02X                                         %c%c%c%c\n",
372             data[c], data[c+1], data[c+2], data[c+3],
373             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]));
374           c += 4;
375           break;
376         case 3:
377           printf(" %02X %02X %02X                                            %c%c%c\n",
378             data[c], data[c+1], data[c+2],
379             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]));
380           c += 3;
381           break;
382         case 2:
383           printf(" %02X %02X                                               %c%c\n",
384             data[c], data[c+1],
385             dcc(data[c]), dcc(data[c+1]));
386           c += 2;
387           break;
388         case 1:
389           printf(" %02X                                                  %c\n",
390             data[c],
391             dcc(data[c]));
392           c += 1;
393           break;
394       }
395     }
396   }
397 }
398
399 unsigned char dcc(UCHAR c)
400 {
401   if (isspace(c)) return ' ';
402   if (isprint(c)) return c;
403   return '.';
404 }
405 */