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