]> git.vomp.tv Git - vompserver.git/blob - bootpd.c
Finished Bootp/TFTP 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   char* tftpFileName = config.getValueString("Boot", "TFTP file name");
226   if (tftpFileName)
227   {
228     strncpy((char*)&data[108], tftpFileName, 127);
229     delete[] tftpFileName;
230   }
231   else
232   {
233     data[108] = '-';
234     data[109] = '\0';
235   }
236
237   // set to reply
238   data[0] = 2;
239
240 //  dump(data, (USHORT)length);
241
242   ds.send("255.255.255.255", 16868, (char*)data, length);
243 }
244
245
246 int Bootpd::getmyip(in_addr_t destination, in_addr_t* result)
247 {
248   int sockfd, r1, r2;
249   struct sockaddr_in my_addr;
250   struct sockaddr_in dest_addr;
251   socklen_t my_addr_len = sizeof(struct sockaddr_in);
252
253   sockfd = socket(AF_INET, SOCK_DGRAM, 0);
254   if (sockfd == -1) return 0;
255
256   dest_addr.sin_family = AF_INET;
257   dest_addr.sin_port = htons(1);
258   dest_addr.sin_addr.s_addr = destination;
259   memset(&(dest_addr.sin_zero), 0, 8);
260
261   r1 = connect(sockfd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr));
262   if (r1 == -1)
263   {
264     close(sockfd);
265     return 0;
266   }
267
268   memset(&my_addr, 0, sizeof(struct sockaddr_in));
269   r2 = getsockname(sockfd, (struct sockaddr *)&my_addr, &my_addr_len);
270
271   close(sockfd);
272
273   if (r2 == -1) return 0;
274
275   *result = my_addr.sin_addr.s_addr;
276   return 1;
277 }
278
279 /*
280 void dump(unsigned char* data, USHORT size)
281 {
282   printf("Size = %u\n", size);
283
284   USHORT c = 0;
285   while(c < size)
286   {
287     if ((size - c) > 15)
288     {
289       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",
290         data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
291         data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], data[c+15],
292         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]),
293         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]));
294       c += 16;
295     }
296     else
297     {
298       switch (size - c)
299       {
300         case 15:
301           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",
302             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
303             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14],
304             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]),
305             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]));
306           c += 15;
307           break;
308         case 14:
309           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",
310             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
311             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13],
312             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]),
313             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]));
314           c += 14;
315           break;
316         case 13:
317           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",
318             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
319             data[c+8], data[c+9], data[c+10], data[c+11], data[c+12],
320             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]),
321             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]));
322           c += 13;
323           break;
324         case 12:
325           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",
326             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
327             data[c+8], data[c+9], data[c+10], data[c+11],
328             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]),
329             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]));
330           c += 12;
331           break;
332         case 11:
333           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X %02X                  %c%c%c%c%c%c%c%c%c%c%c\n",
334             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
335             data[c+8], data[c+9], data[c+10],
336             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]),
337             dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]));
338           c += 11;
339           break;
340         case 10:
341           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X %02X                     %c%c%c%c%c%c%c%c%c%c\n",
342             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
343             data[c+8], data[c+9],
344             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]),
345             dcc(data[c+8]), dcc(data[c+9]));
346           c += 10;
347           break;
348         case 9:
349           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X  %02X                        %c%c%c%c%c%c%c%c%c\n",
350             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
351             data[c+8],
352             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]),
353             dcc(data[c+8]));
354           c += 9;
355           break;
356         case 8:
357           printf(" %02X %02X %02X %02X  %02X %02X %02X %02X                            %c%c%c%c%c%c%c%c\n",
358             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7],
359             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]));
360           c += 8;
361           break;
362         case 7:
363           printf(" %02X %02X %02X %02X  %02X %02X %02X                               %c%c%c%c%c%c%c\n",
364             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6],
365             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]));
366           c += 7;
367           break;
368         case 6:
369           printf(" %02X %02X %02X %02X  %02X %02X                                  %c%c%c%c%c%c\n",
370             data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5],
371             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]));
372           c += 6;
373           break;
374         case 5:
375           printf(" %02X %02X %02X %02X  %02X                                     %c%c%c%c%c\n",
376             data[c], data[c+1], data[c+2], data[c+3], data[c+4],
377             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]));
378           c += 5;
379           break;
380         case 4:
381           printf(" %02X %02X %02X %02X                                         %c%c%c%c\n",
382             data[c], data[c+1], data[c+2], data[c+3],
383             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]));
384           c += 4;
385           break;
386         case 3:
387           printf(" %02X %02X %02X                                            %c%c%c\n",
388             data[c], data[c+1], data[c+2],
389             dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]));
390           c += 3;
391           break;
392         case 2:
393           printf(" %02X %02X                                               %c%c\n",
394             data[c], data[c+1],
395             dcc(data[c]), dcc(data[c+1]));
396           c += 2;
397           break;
398         case 1:
399           printf(" %02X                                                  %c\n",
400             data[c],
401             dcc(data[c]));
402           c += 1;
403           break;
404       }
405     }
406   }
407 }
408
409 unsigned char dcc(UCHAR c)
410 {
411   if (isspace(c)) return ' ';
412   if (isprint(c)) return c;
413   return '.';
414 }
415 */