networkbrowser: reindent nbtscan.c
[enigma2-plugins.git] / networkbrowser / src / lib / nbtscan.c
1 /*###########################################################################
2 #
3 # written by :  Stephen J. Friedl
4 #               Software Consultant
5 #               steve@unixwiz.net
6 #
7 # Copyright (C) 2007 - 2008 by
8 # nixkoenner <nixkoenner@newnigma2.to>
9 # License: GPL
10 #
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 2 of the License, or
14 # (at your option) any later version.
15 #
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
20 #
21 # You should have received a copy of the GNU General Public License
22 # along with this program; if not, write to the Free Software
23 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #
25 ###########################################################################*/
26
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 #include <stdlib.h>
32 #include <sys/time.h>
33 #include <string.h>
34 #include <unistd.h>
35 #include <getopt.h>
36 #if HAVE_STDINT_H
37 #include <stdint.h>
38 #endif
39
40 #include "nbtscan.h"
41
42 int quiet = 0;
43 netinfo *nInfo = 0;
44
45 int set_range(char *range_str, struct ip_range *range_struct)
46 {
47         if (is_ip(range_str, range_struct))
48                 return 1;
49         if (is_range1(range_str, range_struct))
50                 return 1;
51         if (is_range2(range_str, range_struct))
52                 return 1;
53         return 0;
54 };
55
56 int print_header()
57 {
58         printf("%-17s%-17s%-10s%-17s%-17s\n", "IP address", "NetBIOS Name", "Server", "User", "MAC address");
59         printf("------------------------------------------------------------------------------\n");
60         return 0;
61 };
62
63 int python_hostinfo(struct in_addr addr, const struct nb_host_info *hostinfo, netinfo * nInfo, int pos)
64 {
65         int unique;
66         my_uint8_t service;
67
68         sleep(1);
69         service = hostinfo->names[0].ascii_name[15];
70         unique = !(hostinfo->names[0].rr_flags & 0x0080);
71         strncpy(nInfo[pos].name, hostinfo->names[0].ascii_name, 15);
72         strncpy(nInfo[pos].domain, hostinfo->names[1].ascii_name, 15);
73         sprintf(nInfo[pos].service, "%s", (char *)getnbservicename(service, unique, hostinfo->names[0].ascii_name));
74         if (hostinfo->footer) {
75                 sprintf(nInfo[pos].mac, "%02x:%02x:%02x:%02x:%02x:%02x",
76                         hostinfo->footer->adapter_address[0], hostinfo->footer->adapter_address[1],
77                         hostinfo->footer->adapter_address[2], hostinfo->footer->adapter_address[3],
78                         hostinfo->footer->adapter_address[4], hostinfo->footer->adapter_address[5]);
79         }
80         strcpy(nInfo[pos].ip, inet_ntoa(addr));
81         return 0;
82 }
83
84 netinfo *newNetInfo()
85 {
86         netinfo *nInfo = malloc(sizeof(netinfo) * 255);
87         if (!nInfo)
88                 exit(0);        // TODO: besser machen 
89         memset(nInfo, 0, sizeof(netinfo) * 255);
90         return nInfo;
91 }
92
93 void freeNetInfo(netinfo * nInfo)
94 {
95         free(nInfo);
96 }
97
98 #define BUFFSIZE 1024
99 #define MAX 255
100
101 int netInfo(char *pythonIp, netinfo * nInfo)
102 {
103         int timeout = 10000, verbose = 0, use137 = 0, bandwidth = 0, send_ok = 0, hr = 0;
104         extern char *optarg;
105         extern int optind;
106         char *target_string;
107         char *sf = NULL;
108         char *filename = NULL;
109         struct ip_range range;
110         void *buff;
111         int sock;
112         unsigned int addr_size;
113         struct sockaddr_in src_sockaddr, dest_sockaddr;
114         struct in_addr *prev_in_addr = NULL;
115         struct in_addr *next_in_addr;
116         struct timeval select_timeout, last_send_time, current_time, diff_time, send_interval;
117         struct timeval transmit_started, now, recv_time;
118         struct nb_host_info *hostinfo;
119         fd_set *fdsr;
120         fd_set *fdsw;
121         int size;
122         int pos = 0;
123         struct list *scanned;
124         my_uint32_t rtt_base;   /* Base time (seconds) for round trip time calculations */
125         float rtt;              /* most recent measured RTT, seconds */
126         float srtt = 0;         /* smoothed rtt estimator, seconds */
127         float rttvar = 0.75;    /* smoothed mean deviation, seconds */
128         double delta;           /* used in retransmit timeout calculations */
129         int rto, retransmits = 0, more_to_send = 1, i;
130         char errmsg[80];
131         char str[80];
132         FILE *targetlist = NULL;
133         hr = 0;
134         sf = optarg;
135         verbose = 1;
136
137         if ((target_string = strdup(pythonIp)) == NULL) {
138                 err_die("Malloc failed.\n", quiet);
139         }
140         if (!set_range(target_string, &range)) {
141                 printf("Error: %s is not an IP address or address range.\n", target_string);
142                 free(target_string);
143         };
144         /* Finished with options */
145   /*************************/
146
147         /* Prepare socket and address structures */
148   /*****************************************/
149         sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
150         if (sock < 0)
151                 err_die("Failed to create socket", quiet);
152
153         bzero((void *)&src_sockaddr, sizeof(src_sockaddr));
154         src_sockaddr.sin_family = AF_INET;
155         if (use137)
156                 src_sockaddr.sin_port = htons(NB_DGRAM);
157         if (bind(sock, (struct sockaddr *)&src_sockaddr, sizeof(src_sockaddr)) == -1)
158                 err_die("Failed to bind", quiet);
159
160         fdsr = malloc(sizeof(fd_set));
161         if (!fdsr)
162                 err_die("Malloc failed", quiet);
163         FD_ZERO(fdsr);
164         FD_SET(sock, fdsr);
165
166         fdsw = malloc(sizeof(fd_set));
167         if (!fdsw)
168                 err_die("Malloc failed", quiet);
169         FD_ZERO(fdsw);
170         FD_SET(sock, fdsw);
171
172         /* timeout is in milliseconds */
173         //select_timeout.tv_sec = timeout / 1000;
174         //select_timeout.tv_usec = (timeout % 1000) * 1000; /* Microseconds */
175         select_timeout.tv_sec = 60;     /* Default 1 min to survive ARP timeouts */
176         select_timeout.tv_usec = 0;
177
178         addr_size = sizeof(struct sockaddr_in);
179
180         next_in_addr = malloc(sizeof(struct in_addr));
181         if (!next_in_addr)
182                 err_die("Malloc failed", quiet);
183
184         buff = malloc(BUFFSIZE);
185         if (!buff)
186                 err_die("Malloc failed", quiet);
187
188         /* Calculate interval between subsequent sends */
189
190         timerclear(&send_interval);
191         if (bandwidth)
192                 send_interval.tv_usec = (NBNAME_REQUEST_SIZE + UDP_HEADER_SIZE + IP_HEADER_SIZE) * 8 * 1000000 / bandwidth;     /* Send interval in microseconds */
193         else                    /* Assuming 10baseT bandwidth */
194                 send_interval.tv_usec = 1;      /* for 10baseT interval should be about 1 ms */
195         if (send_interval.tv_usec >= 1000000) {
196                 send_interval.tv_sec = send_interval.tv_usec / 1000000;
197                 send_interval.tv_usec = send_interval.tv_usec % 1000000;
198         }
199
200         gettimeofday(&last_send_time, NULL);    /* Get current time */
201
202         rtt_base = last_send_time.tv_sec;
203
204         /* Send queries, receive answers and print results */
205   /***************************************************/
206
207         scanned = new_list();
208
209         for (i = 0; i <= retransmits; i++) {
210                 gettimeofday(&transmit_started, NULL);
211                 while ((select(sock + 1, fdsr, fdsw, NULL, &select_timeout)) > 0) {
212                         if (FD_ISSET(sock, fdsr)) {
213                                 if ((size = recvfrom(sock, buff, BUFFSIZE, 0, (struct sockaddr *)&dest_sockaddr, &addr_size)) <= 0) {
214                                         snprintf(errmsg, 80, "%s\tRecvfrom failed", inet_ntoa(dest_sockaddr.sin_addr));
215                                         err_print(errmsg, quiet);
216                                         continue;
217                                 };
218                                 gettimeofday(&recv_time, NULL);
219                                 memset(&hostinfo, 0, sizeof(hostinfo));
220                                 hostinfo = (struct nb_host_info *)parse_response(buff, size);
221                                 if (!hostinfo) {
222                                         err_print("parse_response returned NULL", quiet);
223                                         continue;
224                                 };
225                                 /* If this packet isn't a duplicate */
226                                 if (insert(scanned, ntohl(dest_sockaddr.sin_addr.s_addr))) {
227                                         rtt = recv_time.tv_sec + recv_time.tv_usec / 1000000 - rtt_base - hostinfo->header->transaction_id / 1000;
228                                         /* Using algorithm described in Stevens' 
229                                            Unix Network Programming */
230                                         delta = rtt - srtt;
231                                         srtt += delta / 8;
232                                         if (delta < 0.0)
233                                                 delta = -delta;
234                                         rttvar += (delta - rttvar) / 4;
235                                         if (hostinfo->names == 0x0) {
236                                                 printf("hostinfo->names == NULL\n");
237                                         } else {
238                                                 python_hostinfo(dest_sockaddr.sin_addr, hostinfo, nInfo, pos);
239                                                 pos++;
240                                         }
241                                 };
242                                 free(hostinfo);
243                         };
244
245                         FD_ZERO(fdsr);
246                         FD_SET(sock, fdsr);
247
248                         /* check if send_interval time passed since last send */
249                         gettimeofday(&current_time, NULL);
250                         timersub(&current_time, &last_send_time, &diff_time);
251                         send_ok = timercmp(&diff_time, &send_interval, >=);
252
253                         if (more_to_send && FD_ISSET(sock, fdsw) && send_ok) {
254                                 if (targetlist) {
255                                         if (fgets(str, 80, targetlist)) {
256                                                 if (!inet_aton(str, next_in_addr)) {
257                                                         /* if(!inet_pton(AF_INET, str, next_in_addr)) { */
258                                                         fprintf(stderr, "%s - bad IP address\n", str);
259                                                 } else {
260                                                         if (!in_list(scanned, ntohl(next_in_addr->s_addr)))
261                                                                 send_query(sock, *next_in_addr, rtt_base);
262                                                 }
263                                         } else {
264                                                 if (feof(targetlist)) {
265                                                         more_to_send = 0;
266                                                         FD_ZERO(fdsw);
267                                                         /* timeout is in milliseconds */
268                                                         select_timeout.tv_sec = timeout / 1000;
269                                                         select_timeout.tv_usec = (timeout % 1000) * 1000;       /* Microseconds */
270                                                         continue;
271                                                 } else {
272                                                         snprintf(errmsg, 80, "Read failed from file %s", filename);
273                                                         err_die(errmsg, quiet);
274                                                 }
275                                         }
276                                 } else if (next_address(&range, prev_in_addr, next_in_addr)) {
277                                         if (!in_list(scanned, ntohl(next_in_addr->s_addr)))
278                                                 send_query(sock, *next_in_addr, rtt_base);
279                                         prev_in_addr = next_in_addr;
280                                         /* Update last send time */
281                                         gettimeofday(&last_send_time, NULL);
282                                 } else {        /* No more queries to send */
283                                         more_to_send = 0;
284                                         FD_ZERO(fdsw);
285                                         /* timeout is in milliseconds */
286                                         select_timeout.tv_sec = timeout / 1000;
287                                         select_timeout.tv_usec = (timeout % 1000) * 1000;       /* Microseconds */
288                                         continue;
289                                 };
290                         };
291                         if (more_to_send) {
292                                 FD_ZERO(fdsw);
293                                 FD_SET(sock, fdsw);
294                         };
295                 };
296
297                 if (i >= retransmits)
298                         break;  /* If we are not going to retransmit
299                                    we can finish right now without waiting */
300
301                 rto = (srtt + 4 * rttvar) * (i + 1);
302
303                 if (rto < 2.0)
304                         rto = 2.0;
305                 if (rto > 60.0)
306                         rto = 60.0;
307                 gettimeofday(&now, NULL);
308
309                 if (now.tv_sec < (transmit_started.tv_sec + rto))
310                         sleep((transmit_started.tv_sec + rto) - now.tv_sec);
311                 prev_in_addr = NULL;
312                 more_to_send = 1;
313                 FD_ZERO(fdsw);
314                 FD_SET(sock, fdsw);
315                 FD_ZERO(fdsr);
316                 FD_SET(sock, fdsr);
317         };
318
319         delete_list(scanned);
320         if (buff) {
321                 free(buff);
322         }
323         return 0;
324         exit(0);
325 };