From: Steinar H. Gunderson Date: Thu, 18 Apr 2019 15:25:39 +0000 (+0200) Subject: Import nbtscanner 0.1.0. X-Git-Url: https://git.sesse.net/?p=nbtscanner;a=commitdiff_plain;h=c00b46344cce7b05d6e0db74359de1971d2d09ec Import nbtscanner 0.1.0. --- c00b46344cce7b05d6e0db74359de1971d2d09ec diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..e77696a --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4d7b6a1 --- /dev/null +++ b/Makefile @@ -0,0 +1,54 @@ +# change for your CPU and compiler + +# note that mysql_config is braindamaged ;-) +CC=gcc +CFLAGS=-g -Wall "`mysql_config --cflags | tr -d \'`" + +LIBS=`mysql_config --libs | tr -d \'` # '` +LDFLAGS=-lefence + +# +# *** end of configuration *** +# + +# due to some icky programming, we will have to add all the .o files everywhere. + +OBJSN=nbtscanner.o mysql_interface.o configfile.o nmb.o stats.o socket.o util.o id_list.o +OBJSO=outputfile.o mysql_interface.o configfile.o nmb.o stats.o socket.o util.o id_list.o + +all: nbtscanner outputfile +nbtscanner: $(OBJSN) + $(CC) -o nbtscanner $(OBJSN) $(LIBS) +outputfile: $(OBJSO) + $(CC) -o outputfile $(OBJSO) $(LIBS) + +nbtscanner.o: nbtscanner.c nbtscanner.h configfile.h mysql_interface.h nmb.h socket.h stats.h \ + packet.h byteorder.h util.h id_list.h + $(CC) $(CFLAGS) -c nbtscanner.c +outputfile.o: outputfile.c configfile.h mysql_interface.h + $(CC) $(CFLAGS) -c outputfile.c + +mysql_interface.o: mysql_interface.c mysql_interface.h + $(CC) $(CFLAGS) -c mysql_interface.c + +configfile.o: configfile.c configfile.h nbtscanner.h + $(CC) $(CFLAGS) -c configfile.c + +nmb.o: nmb.c nmb.h packet.h byteorder.h util.h + $(CC) $(CFLAGS) -c nmb.c + +stats.o: stats.c stats.h configfile.h util.h + $(CC) $(CFLAGS) -c stats.c + +socket.o: socket.c socket.h nmb.h packet.h + $(CC) $(CFLAGS) -c socket.c + +util.o: util.c util.h + $(CC) $(CFLAGS) -c util.c + +id_list.o: id_list.c id_list.h configfile.h util.h + $(CC) $(CFLAGS) -c id_list.c + +.PHONY: clean +clean: + rm -f $(OBJSO) $(OBJSN) nbtscanner outputfile diff --git a/README b/README new file mode 100644 index 0000000..01ec31d --- /dev/null +++ b/README @@ -0,0 +1,7 @@ +This program is GPLed, v2. No documentation exists yet -- use common +sense and read the source :-) + +This program borrows considerable amount of code from Samba, and would +not be possible at all without it. Big thanks to the Samba team :-) + +- Steinar H. Gunderson diff --git a/byteorder.h b/byteorder.h new file mode 100644 index 0000000..e90b3d7 --- /dev/null +++ b/byteorder.h @@ -0,0 +1,40 @@ +/* + * nbtscanner -- a tool for scanning large networks for SMB servers. + * + * byteorder.h: structure access functions (i386 only!). + * Copyright (C) 2000 Steinar H. Gunderson + * + * Large amounts of code adapted from Samba (http://www.samba.org/) + * Copyright (C) Andrew Tridgell 1994-1998, and others. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _BYTEORDER_H +#define _BYTEORDER_H 1 + +#define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16) +#define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF)) +#define SVAL(buf,pos) (*(unsigned short *)((char *)(buf) + (pos))) +#define SSVAL(buf,pos,val) SVAL(buf,pos)=((unsigned short)(val)) +#define RSSVAL(buf,pos,val) SSVAL(buf,pos,SREV(val)) +#define RSVAL(buf,pos) SREV(SVAL(buf,pos)) +#define CVAL(buf,pos) (((unsigned char *)(buf))[pos]) +#define RIVAL(buf,pos) IREV(IVAL(buf,pos)) +#define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16))) + +#define PTR_DIFF(p1,p2) ((ptrdiff_t)(((const char *)(p1)) - (const char *)(p2))) + +#endif /* _BYTEORDER_H */ diff --git a/configfile.c b/configfile.c new file mode 100644 index 0000000..3b15403 --- /dev/null +++ b/configfile.c @@ -0,0 +1,255 @@ +/* + * nbtscanner -- a tool for scanning large networks for SMB servers. + * + * configfile.c: Functions for parsing the configuration file. + * Copyright (C) 2000 Steinar H. Gunderson + * + * Large amounts of code adapted from Samba (http://www.samba.org/) + * Copyright (C) Andrew Tridgell 1994-1998, and others. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "configfile.h" +#include "nbtscanner.h" +#include "mysql_interface.h" + +#include +#include +#include +#include +#include +#include + +int num_retries; +int retry_time; +int delay_time; +int verbosity; + +int use_mysql; +char mysql_host[64]; +char mysql_username[32]; +char mysql_password[32]; + +void parse_configfile(int do_scan) +{ + FILE *configfile = fopen("nbtscanner.conf", "r"); + int lineno = 0; + + if (configfile == NULL) { + perror("nbtscanner.conf"); + exit(1); + } + + /* defaults */ + num_retries = 3; + retry_time = 5000; + delay_time = 100; + verbosity = 2; + + use_mysql = 0; + strcpy(mysql_host, "no_host_given"); + strcpy(mysql_username, "no_username_given"); + strcpy(mysql_password, "no_password_given"); + + while (!feof(configfile)) { + char buf[1024]; + + lineno++; + + fgets(buf, 1024, configfile); + while (buf[strlen(buf) - 1] == '\n' || buf[strlen(buf) - 1] == '\r') { + buf[strlen(buf) - 1] = '\0'; + } + + if (buf[0] == '#' || buf[0] == '\0') { + /* comment or blank line */ + continue; + } + if (strspn(buf, " \t") == strlen(buf)) { + /* blank line */ + continue; + } + + parse_line(buf, lineno, do_scan); + } + + fclose(configfile); +} + +void parse_line(char *buf, int lineno, int do_scan) +{ + char *ptr = strchr(buf, '='); + + if (ptr == NULL || strchr(ptr + 1, '=') != NULL) { + line_error(lineno, "Malformed line (must be exactly one `=' sign)"); + } + + /* split the line into a keyword and a value */ + ptr[0] = 0; + ptr++; + + /* + * trim any trailing spaces, make sure there are no spaces in + * the value + */ + { + char *ptr2 = strchr(ptr, ' '); + if (ptr2 != NULL) { + /* must only be spaces from here */ + if (strspn(ptr2 + 1, " ") != strlen(ptr2 + 1)) { + line_error(lineno, "Malformed value (can't have any spaces)"); + } + + ptr2[0] = 0; + } + } + + /* make sure both the parameter and the value is non-empty */ + if (buf[0] == '\0') { + line_error(lineno, "Malformed keyword (can't be empty)"); + } + if (ptr[0] == '\0') { + line_error(lineno, "Malformed value (can't be empty)"); + } + + /* finally pass it on to the keyword checker */ + parse_keyword(buf, ptr, lineno, do_scan); +} + +void parse_keyword(char *keyword, char *value, int lineno, int do_scan) +{ + if (strcasecmp(keyword, "num_retries") == 0) { + parse_int(value, &num_retries, lineno); + } else if (strcasecmp(keyword, "retry_time") == 0) { + parse_int(value, &retry_time, lineno); + } else if (strcasecmp(keyword, "delay_time") == 0) { + parse_int(value, &delay_time, lineno); + } else if (strcasecmp(keyword, "verbosity") == 0) { + parse_int(value, &verbosity, lineno); + } else if (strcasecmp(keyword, "use_mysql") == 0) { + parse_int(value, &use_mysql, lineno); + } else if (strcasecmp(keyword, "mysql_host") == 0) { + strcpy(mysql_host, value); + } else if (strcasecmp(keyword, "mysql_username") == 0) { + strcpy(mysql_username, value); + } else if (strcasecmp(keyword, "mysql_password") == 0) { + strcpy(mysql_password, value); + } else if (strcasecmp(keyword, "range") == 0) { + /* really ugly to have here */ + if (use_mysql) { + init_mysql(mysql_host, mysql_username, mysql_password); + } + if (do_scan) parse_range(value, lineno); + } else { + char buf[1024]; + sprintf(buf, "Unknown keyword `%s'", keyword); + line_error(lineno, buf); + } +} + +void parse_int(char *string, int *retval, int lineno) +{ + if (strspn(string, "0123456789") != strlen(string)) { + char buf[1024]; + sprintf(buf, "`%s' isn't a positive integer", string); + line_error(lineno, buf); + } + + *retval = atoi(string); +} + +void parse_range(char *string, int lineno) +{ + /* exactly one / is allowed */ + char *ptr = strchr(string, '/'); + struct in_addr in; + int rangesize; + + if (ptr != NULL && strchr(ptr + 1, '/') != NULL) { + line_error(lineno, "Malformed range (only one `/' allowed)"); + } + + /* lots and lots of code :-) */ + if (ptr == NULL) { /* single IP */ + rangesize = 32; + } else { /* range */ + ptr[0] = 0; + ptr++; + + /* find out whether this is a pure integer or not */ + if (strspn(ptr, "0123456789") == strlen(ptr)) { + rangesize = atoi(ptr); + if (rangesize < 0 || rangesize > 32) { + line_error(lineno, "Malformed range (significant bits must be between 0 and 32, inclusive)"); + } + } else if (strspn(ptr, "0123456789.") == strlen(ptr)) { + /* IP address... */ + struct in_addr netmask; + int found, i; + + if (inet_aton(ptr, &netmask) == 0) { + line_error(lineno, "Malformed range (malformed netmask)"); + } + + /* find the rightmost 1-bit (by finding the leftmost 0-bit) */ + found = 0; + for (i = 31; i >= 0; i--) { + if ((netmask.s_addr & (1 << i)) == 0) { + found = 1; + break; + } + } + if (found == 0) { + rangesize = 32; /* 255.255.255.255 */ + } else { + unsigned int clean_mask = htonl(~((1 << (31-i)) - 1)); + + rangesize = i + 1; + + /* verify that this is a `clean' netmask */ + if (netmask.s_addr != clean_mask) { + line_error(lineno, "Malformed range (netmask must be `clean')"); + } + } + } else { + line_error(lineno, "Malformed range (malformed netmask)"); + rangesize = 32; /* will never reach this, but for gcc */ + } + } + + /* try to scan the IP part */ + if (inet_aton(string, &in) == 0) { + line_error(lineno, "Malformed range (malformed IP address)"); + } + + /* check that the IP address and the netmask match */ + if (rangesize != 32) { + /* not really the netmask, actually it's the inverted netmask */ + unsigned int netmask = htonl((1 << (31-rangesize)) - 1); + + if ((in.s_addr & netmask) != 0) { + line_error(lineno, "Malformed range (IP address doesn't match netmask)"); + } + } + + scan_range(in, rangesize); +} + +void line_error(int lineno, char *err_str) +{ + fprintf(stderr, "nbtscanner.conf:%d: %s\n", lineno, err_str); + exit(1); +} diff --git a/configfile.h b/configfile.h new file mode 100644 index 0000000..767d4be --- /dev/null +++ b/configfile.h @@ -0,0 +1,46 @@ +/* + * nbtscanner -- a tool for scanning large networks for SMB servers. + * + * configfile.h: Prototypes for configfile.c. + * Copyright (C) 2000 Steinar H. Gunderson + * + * Large amounts of code adapted from Samba (http://www.samba.org/) + * Copyright (C) Andrew Tridgell 1994-1998, and others. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _CONFIGFILE_H +#define _CONFIGFILE_H 1 + +extern int num_retries; +extern int retry_time; +extern int delay_time; +extern int verbosity; + +extern int use_mysql; +extern char mysql_host[64]; +extern char mysql_username[32]; +extern char mysql_password[32]; + +void parse_configfile(int do_scan); +void parse_line(char *buf, int lineno, int do_scan); +void parse_keyword(char *keyword, char *value, int lineno, int do_scan); +void parse_int(char *string, int *retval, int lineno); +void parse_range(char *string, int lineno); + +void line_error(int lineno, char *err_str); + +#endif diff --git a/id_list.c b/id_list.c new file mode 100644 index 0000000..36676d4 --- /dev/null +++ b/id_list.c @@ -0,0 +1,134 @@ +/* + * nbtscanner -- a tool for scanning large networks for SMB servers. + * + * id_list.c: a singly linked list for keeping track of the packet IDs. + * Copyright (C) 2000 Steinar H. Gunderson + * + * Large amounts of code adapted from Samba (http://www.samba.org/) + * Copyright (C) Andrew Tridgell 1994-1998, and others. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "id_list.h" +#include "configfile.h" +#include "util.h" + +#include +#include +#include +#include + +struct id_entry ids[65536]; +struct id_list_entry *head_free_id; +int num_free_ids; + +void id_list_init() +{ + int i, start_num; + + num_free_ids = 0; + head_free_id = NULL; + + /* we want to start at some halfway random number instead of 0 */ + start_num = (time(NULL) + getpid()) & 0xffff; + + for (i = 65535; i >= 0; i--) { + int ii = (i + start_num) & 0xffff; + + ids[ii].id = ii; + ids[ii].in_use = 0; + + id_free(&ids[ii]); + } +} + +void id_free(struct id_entry *i) +{ + struct id_list_entry *ie = (struct id_list_entry *)malloc(sizeof(struct id_list_entry)); + + if (ie == NULL) { + perror("malloc()"); + exit(1); + } + + i->in_use = 0; + ie->id = i; + + /* insert at the beginning of the linked list */ + ie->next = head_free_id; + head_free_id = ie; + + num_free_ids++; +} + +/* mark as free, but don't delete until desperation cleanup */ +void id_mark_free(struct id_entry *i) +{ + i->in_use = 2; + num_free_ids++; +} + +struct id_entry *id_get_free_id() +{ + struct id_list_entry *ie = head_free_id; + struct id_entry *i; + + if (ie == NULL) { + return NULL; + } else { + i = ie->id; + head_free_id = ie->next; + free(ie); + + i->in_use = 1; + num_free_ids--; + + return i; + } +} + +/* desperation time :-) */ +int id_cleanup(int timeout_ms) +{ + int i; + int num_freed = 0; + struct timeval now; + gettimeofday(&now, NULL); + + for (i = 0; i < 65536; i++) { + if (ids[i].in_use == 2) { + id_free(&ids[i]); + num_freed++; + num_free_ids--; /* was already counted */ + + continue; + } + if (mydifftime(ids[i].timestamp, now) > timeout_ms && + ids[i].retries == num_retries) { + id_free(&ids[i]); + num_freed++; + + continue; + } + } + + return num_freed; +} + +int get_num_free_ids() +{ + return num_free_ids; +} diff --git a/id_list.h b/id_list.h new file mode 100644 index 0000000..3a37d7b --- /dev/null +++ b/id_list.h @@ -0,0 +1,73 @@ +/* + * nbtscanner -- a tool for scanning large networks for SMB servers. + * + * id_list.h: Prototypes and structures for keeping track of the packet IDs. + * Copyright (C) 2000 Steinar H. Gunderson + * + * Large amounts of code adapted from Samba (http://www.samba.org/) + * Copyright (C) Andrew Tridgell 1994-1998, and others. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _ID_LIST_H +#define _ID_LIST_H 1 + +#include +#include + +/* + * There's quite some data duplication here, in the interest of speed and code + * simplicity. + */ + +struct id_entry { + unsigned short id; /* ID number from NBT packet */ + int in_use; /* Are we awaiting a reply on this ID? */ + + struct in_addr sin; /* IP address we've sent it to */ + struct timeval timestamp; /* When we sent the packet */ + int retries; /* Number of retries tried */ + + /* we list on index entry instead of using pointers */ + int prev_index; + int next_index; +}; + +struct id_list_entry { + struct id_list_entry *next; + struct id_entry *id; +}; + +/* + * a list of all the available ID numbers (sin is unused, in_use = 0) + * + * We could have a used_id list as well, but it would require a doubly + * linked list, and perhaps doesn't help all that much anyways + */ +extern struct id_list_entry *head_free_id; + +/* an array with a one-to-one mapping of the array index vs. the id field */ +extern struct id_entry ids[]; + +void id_list_init(); +void id_free(struct id_entry *i); +void id_mark_free(struct id_entry *i); +struct id_entry *id_get_free_id(); +int id_cleanup(int timeout_ms); +int get_num_free_ids(); + +#endif /* _ID_LIST_H */ + diff --git a/init.sql b/init.sql new file mode 100644 index 0000000..29b4a25 --- /dev/null +++ b/init.sql @@ -0,0 +1,17 @@ +USE mysql; +INSERT INTO mysql.user (Host, User, Password) VALUES('%', 'nbtscanner', PASSWORD('tg01')); +INSERT INTO mysql.user (Host, User, Password) VALUES('localhost', 'nbtscanner', PASSWORD('tg01')); +FLUSH PRIVILEGES; + +CREATE DATABASE nbtscanner; +USE nbtscanner; +CREATE TABLE nbtscanner ( + ip CHAR(16) NOT NULL, + hostname CHAR(32), + fileservername CHAR(32), + groupname CHAR(32), + PRIMARY KEY ( + ip + ) +); +GRANT INSERT, UPDATE, DELETE ON nbtscanner.nbtscanner TO nbtscanner@"%" IDENTIFIED BY 'tg01'; diff --git a/mysql_interface.c b/mysql_interface.c new file mode 100644 index 0000000..c51633a --- /dev/null +++ b/mysql_interface.c @@ -0,0 +1,138 @@ +/* + * nbtscanner -- a tool for scanning large networks for SMB servers. + * + * mysql_interface.c: Interface routines for the MySQL table. + * Copyright (C) 2000 Steinar H. Gunderson + * + * Large amounts of code adapted from Samba (http://www.samba.org/) + * Copyright (C) Andrew Tridgell 1994-1998, and others. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include + +#include "mysql_interface.h" +#include "configfile.h" + +MYSQL *mysql = NULL; + +/* veeeery detailed error reporting here ;-) */ +void init_mysql(char *host, char *username, char *password) +{ + if (mysql != NULL) return; /* hack */ + + mysql = mysql_init(NULL); + if (mysql == NULL) { + if (verbosity >= 1) { + fprintf(stderr, "mysql_init() failed\n"); + } + exit(1); + } + + if (mysql_real_connect(mysql, mysql_host, username, password, "nbtscanner", + 0, NULL, 0) == 0) { + if (verbosity >= 1) { + fprintf(stderr, "mysql_real_connect() failed\n"); + } + exit(1); + } +} + +void add_record_mysql(char *ip, char *hostname, char *fileservername, char *groupname) +{ + char query[256]; + snprintf(query, 256, + "REPLACE INTO nbtscanner.nbtscanner SET ip='%s', hostname='%s', fileservername='%s', groupname='%s';", + ip, hostname, fileservername, groupname); + + if (mysql_query(mysql, query) != 0) { + if (verbosity >= 1) { + fprintf(stderr, "mysql_query(`%s') failed\n", query); + } + exit(1); + } +} + +void delete_record_mysql(char *ip) +{ + char query[256]; + snprintf(query, 256, + "DELETE FROM nbtscanner.nbtscanner WHERE ip='%s';", + ip); + + if (mysql_query(mysql, query) != 0) { + if (verbosity >= 1) { + fprintf(stderr, "mysql_query(`%s') failed\n", query); + } + exit(1); + } +} + +void print_all_records_mysql() +{ + MYSQL_RES *result; + unsigned long *lengths; + unsigned int num_fields; + int i; + + if (mysql_query(mysql, "SELECT ip,fileservername,groupname,(fileservername <> '-unknown-nbtscanner-') FROM nbtscanner.nbtscanner;") != 0) { + if (verbosity >= 1) { + fprintf(stderr, "mysql_query('SELECT ip'...) failed\n"); + } + exit(1); + } + + result = mysql_store_result(mysql); + if (result == NULL) { + if (verbosity >= 1) { + fprintf(stderr, "mysql_store_result() failed\n"); + } + exit(1); + } + + num_fields = mysql_num_fields(result); + while (1) { + MYSQL_ROW row = mysql_fetch_row(result); + if (row == NULL) return; + + lengths = mysql_fetch_lengths(result); + + for (i = 0; i < num_fields; i++) { + int j; + + /* strip away CR/LFs */ + for (j = 0; j < lengths[i]; j++) { + if (row[i][j] == 0 || row[i][j] == 10 || row[i][j] == 13) { + row[i][j] = '?'; + } + } + printf("%.*s", (int) lengths[i], row[i] ? row[i] : "NULL"); + if (i != num_fields - 1) putchar(0); + } + printf("\r\n"); + } +} + +void finish_mysql() +{ + /* don't care if this fails */ + mysql_query(mysql, "OPTIMIZE TABLE nbtscanner.nbtscanner;"); + + mysql_close(mysql); +} + diff --git a/mysql_interface.h b/mysql_interface.h new file mode 100644 index 0000000..26565dc --- /dev/null +++ b/mysql_interface.h @@ -0,0 +1,34 @@ +/* + * nbtscanner -- a tool for scanning large networks for SMB servers. + * + * mysql_interface.c: Interface routines for the MySQL table. + * Copyright (C) 2000 Steinar H. Gunderson + * + * Large amounts of code adapted from Samba (http://www.samba.org/) + * Copyright (C) Andrew Tridgell 1994-1998, and others. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _MYSQL_INTERFACE_H +#define _MYSQL_INTERFACE_H 1 + +void init_mysql(char *host, char *username, char *password); +void add_record_mysql(char *ip, char *hostname, char *fileservername, char *groupname); +void delete_record_mysql(char *ip); +void print_all_records_mysql(); +void finish_mysql(); + +#endif /* _MYSQL_INTERFACE_H */ diff --git a/nbtscanner.c b/nbtscanner.c new file mode 100644 index 0000000..a7c5e25 --- /dev/null +++ b/nbtscanner.c @@ -0,0 +1,338 @@ +/* + * nbtscanner -- a tool for scanning large networks for SMB servers. + * + * nbtscanner.c: nbtscanner main body. + * Copyright (C) 2000 Steinar H. Gunderson + * + * Large amounts of code adapted from Samba (http://www.samba.org/) + * Copyright (C) Andrew Tridgell 1994-1998, and others. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nbtscanner.h" +#include "mysql_interface.h" +#include "configfile.h" +#include "nmb.h" +#include "socket.h" +#include "stats.h" +#include "packet.h" +#include "byteorder.h" +#include "util.h" +#include "id_list.h" + +/* one global variable -- the UDP socket */ +int server_fd; + +void interpret_node_status(char *p, struct in_addr in) +{ + int numnames = CVAL(p,0); + char hostname[32], fileservername[32], group[32]; + + /* + * hopefully this will be enough to identify the host as unknown + * (note that this is longer than the 16 char maximum NetBIOS + * name length) + */ + strcpy(hostname, "-unknown-nbtscanner-"); + strcpy(fileservername, "-unknown-nbtscanner-"); + strcpy(group, "-unknown-nbtscanner-"); + + p += 1; + while (numnames--) { + char qname[17]; + int type; + int i; + + strncpy(qname,p,15); + qname[15] = 0; + type = CVAL(p,15); + p += 16; + + for (i = strlen(qname); --i >= 0; ) { + if (!isprint((int)qname[i])) qname[i] = '.'; + } + + /* + * this is code duplication (see parse_nmb_name in nmb.c) + * but it obviously isn't done in our case :-) + */ + for (i = strlen(qname); --i >= 0; ) { + if (qname[i] == ' ') { + qname[i] = 0; + } else { + break; + } + } + + /* , non- server hostname (type 0x00) */ + if ((p[0] & 0x80) == 0x00 && ((p[0] & 0x1f) == 0x04) && type == 0x00) { + strcpy(hostname, qname); + } + /* , non- server hostname (type 0x20) */ + if ((p[0] & 0x80) == 0x00 && ((p[0] & 0x1f) == 0x04) && type == 0x20) { + strcpy(fileservername, qname); + } + /* , group (type 0x00) */ + if ((p[0] & 0x80) == 0x80 && ((p[0] & 0x1f) == 0x04) && type == 0x00) { + strcpy(group, qname); + } + + p += 2; + } + + if (use_mysql) { + add_record_mysql(inet_ntoa(in), hostname, fileservername, group); + } else { + printf("%s,%s,%s,%s\n", inet_ntoa(in), hostname, fileservername, group); + } +} + +void resend_timed_out_packets(int fd) +{ + int i; + struct timeval now; + struct nmb_packet nmb; + + gettimeofday(&now, NULL); + + for (i = 0; i < 65536; i++) { + if (ids[i].in_use == 1 && + mydifftime(ids[i].timestamp, now) > retry_time) { + if (ids[i].retries >= num_retries) { + id_mark_free(&ids[i]); + + num_failed++; + if (use_mysql) { + delete_record_mysql(inet_ntoa(ids[i].sin)); + } + print_stats(0); + } else { + gettimeofday(&(ids[i].timestamp), NULL); + ids[i].retries++; + num_sent_total++; + + build_nbt_packet(&nmb, i); + send_packet(&nmb, ids[i].sin, 137, fd); + recv_nbt_packets(fd); /* delay and empty buffer */ + print_stats(0); + } + } + } +} + +void send_nbt_packet(int fd, struct in_addr to_ip) +{ + struct nmb_packet nmb; + static int name_trn_id = 0; + struct id_entry *i = id_get_free_id(); + + if (i == NULL) { + /* uh-oh... try to remove timed-out IDs */ + if (id_cleanup(retry_time + 1000) == 0 || + (i=id_get_free_id()) == NULL) { + if (verbosity >= 1) { + fprintf(stderr, "No free NBT IDs! Reduce " + "the number of hosts, the " + "number\n"); + fprintf(stderr, "of retries, or the scanning " + "speed. nbtscanner is now " + "exiting.\n"); + } + exit(1); + } + } + name_trn_id = i->id; + i->sin = to_ip; + gettimeofday(&(i->timestamp), NULL); + i->retries = 0; + + build_nbt_packet(&nmb, name_trn_id); + + /* FIXME: what to do with sending errors? */ + send_packet(&nmb, to_ip, 137, fd); + + num_sent++; + num_sent_total++; + print_stats(0); +} + +/* + * This function not only receives and handles any NBT replies, but + * also guarantees a delay of minimum delay_time. + */ +void recv_nbt_packets(int fd) +{ + struct nmb_packet *nmb; + struct in_addr in; + struct timeval start; + int dt = delay_time; + + gettimeofday(&start, NULL); + + while (dt > 0) { + struct timeval now; + + print_stats(0); + + gettimeofday(&now, NULL); + dt = delay_time - mydifftime(start, now); + + if (dt < 0) break; + + nmb = receive_packet(fd, dt, &in); + if (nmb) { + struct id_entry *i = &ids[nmb->header.name_trn_id]; + + if (!nmb->header.response) { + /* It's not for us */ + free_nmb_packet(nmb); + continue; + } + if (i->in_use == 0) { + if (verbosity < 2) continue; + + fprintf(stderr, "Warning: received NBT " + "response for unused " + "id %04x!\n", + i->id); + continue; + } + if (i->in_use == 2) { + if (verbosity < 2) continue; + + fprintf(stderr, "Warning: received " + "duplicate NBT response " + "for id %04x!\n", + i->id); + continue; + } + if (in.s_addr != i->sin.s_addr) { + char got_addr[32], want_addr[32]; + + if (verbosity < 2) continue; + + strcpy(got_addr, inet_ntoa(in)); + strcpy(want_addr, inet_ntoa(i->sin)); + + fprintf(stderr, "Warning: received NBT " + "response for id %04x " + "from %s instead of %s!\n", + i->id, got_addr, want_addr); + continue; + } + + if (nmb->header.opcode != 0 || + nmb->header.nm_flags.bcast || + nmb->header.rcode || + !nmb->header.ancount || + nmb->answers->rr_type != 0x21) { + /* XXXX what do we do with this? could be a redirect, but + we'll discard it for the moment */ + free_nmb_packet(nmb); + continue; + } + + num_recv++; + num_recv_retries = i->retries; + + interpret_node_status(&nmb->answers->rdata[0], in); + free_nmb_packet(nmb); + + id_mark_free(i); + } + } +} + +void scan_range(struct in_addr ip, int rangesize) +{ + if (rangesize == 32) { + /* scan a single IP */ + send_nbt_packet(server_fd, ip); + recv_nbt_packets(server_fd); + } else if (rangesize == 31) { + /* scan two IPs */ + send_nbt_packet(server_fd, ip); + recv_nbt_packets(server_fd); + + ip.s_addr = htonl(ntohl(ip.s_addr) + 1); + send_nbt_packet(server_fd, ip); + recv_nbt_packets(server_fd); + } else { + /* scan a range of IPs, minus the top and bottom one */ + int i; + + ip.s_addr = htonl(ntohl(ip.s_addr) + 1); /* skip bottom */ + + for (i = 0; i < (1 << (32-rangesize)) - 2; i++) { + send_nbt_packet(server_fd, ip); + recv_nbt_packets(server_fd); + + ip.s_addr = htonl(ntohl(ip.s_addr) + 1); + } + } +} + +int main(int argc, char *argv[]) +{ + int fd = open_sockets(); + + id_list_init(); + init_stats(); + + /* note that parse_configfile() will call scan_range()! */ + server_fd = fd; + parse_configfile(1); + +/* for (i=1;i= 3) { + print_stats(1); + fprintf(stderr, "\n"); + } + + return 0; +} diff --git a/nbtscanner.conf b/nbtscanner.conf new file mode 100644 index 0000000..06da5e7 --- /dev/null +++ b/nbtscanner.conf @@ -0,0 +1,72 @@ +# +# nbtscanner.conf example +# +# Note that the config file scanner is not very smart, so you'd +# better be a bit restrictive here :-) (In particular, don't forget +# a newline at the end, and the ranges MUST come after the settings, +# otherwise you'll get slightly weird results :-) ) +# +# This file is case-insensitive. +# + +# The number of retries each host should be allowed to have. +num_retries=3 + +# The amount of time between each retry, in milliseconds. +retry_time=5000 + +# How long nbtscanner will delay between each sent packet, in ms. +delay_time=100 + +# Verbosity level: +# 0: Absolutely no warnings or error messages will be printed (not +# recommended, it's kinda nice to know why the program failed). +# 1: Fatal error messages will be printed on standard error. +# 2: Warnings (like suspicious NBT responses coming in, etc.) are +# also printed. +# 3: Errors, warnings and progress indicators. +# +# Config file errors are printed regardless of this setting. It's +# recommended that you redirect standard output to a file (or a +# pipe) if using verbosity >= 1. +# +verbosity=3 + +# +# MySQL setup +# +# If this is 1, a MySQL connection is used instead of outputting +# all the IPs to standard output. This is highly recommended, but +# needs some table setup before use. +# +use_mysql=1 + +# +# Your MySQL server information. mysql_host is the IP address (or +# host name) of your MySQL server, often localhost. mysql_username +# and password_username have obvious meanings. The password is in +# cleartext, so make sure the permissions on this file are set to +# 0600 or similiar. +# +mysql_host=127.0.0.1 +mysql_username=nbtscanner +mysql_password=tg01 + +# +# Each IP address range is specified with a range= parameter. +# There are three different ways to specify these: +# +# range=10.0.0.1 -- scan one IP address only. +# range=10.0.0.0/24 -- scan an entire C-net. +# range=10.0.0.0/255.255.255.0 -- the same, using netmask notation. +# +# If you specify networks, the top and bottom address will not be +# scanned. Netmasks must be filled from the left (if you don't have +# a VERY weird network layout, this will come naturally). +# +# Duplicate IP address _will_ be scanned twice. :-) +# +range=10.0.7.80/28 +# range=10.0.0.0/24 +range=10.0.19.0/24 + diff --git a/nbtscanner.h b/nbtscanner.h new file mode 100644 index 0000000..991bf45 --- /dev/null +++ b/nbtscanner.h @@ -0,0 +1,39 @@ +/* + * nbtscanner -- a tool for scanning large networks for SMB servers. + * + * nbtscanner.c: Prototypes for nbtscanner.c. + * Copyright (C) 2000 Steinar H. Gunderson + * + * Large amounts of code adapted from Samba (http://www.samba.org/) + * Copyright (C) Andrew Tridgell 1994-1998, and others. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _NBTSCANNER_H +#define _NBTSCANNER_H 1 + +#include + +void interpret_node_status(char *p, struct in_addr in); +void resend_timed_out_packets(int fd); +void send_nbt_packet(int fd, struct in_addr to_ip); +void recv_nbt_packets(int fd); + +void scan_range(struct in_addr ip, int rangesize); +int main(int argc, char *argv[]); + +#endif /* _NBTSCANNER_H */ + diff --git a/nmb.c b/nmb.c new file mode 100644 index 0000000..bb89ba9 --- /dev/null +++ b/nmb.c @@ -0,0 +1,354 @@ +/* + * nbtscanner -- a tool for scanning large networks for SMB servers. + * + * nmb.c: Most functions directly related to the NMB protocol. + * + * Large amounts of code adapted from Samba (http://www.samba.org/) + * Copyright (C) Andrew Tridgell 1994-1998, and others. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include +#include +#include +#include + +#include "nmb.h" +#include "packet.h" +#include "byteorder.h" +#include "util.h" + +void build_nbt_packet(struct nmb_packet *nmb, int name_trn_id) +{ + nmb->header.name_trn_id = name_trn_id; + nmb->header.opcode = 0; + nmb->header.response = 0; + nmb->header.nm_flags.bcast = 0; + nmb->header.nm_flags.recursion_available = 0; + nmb->header.nm_flags.recursion_desired = 0; + nmb->header.nm_flags.trunc = 0; + nmb->header.nm_flags.authoritative = 0; + nmb->header.rcode = 0; + nmb->header.qdcount = 1; + nmb->header.ancount = 0; + nmb->header.nscount = 0; + nmb->header.arcount = 0; + + make_nmb_name(&(nmb->question.question_name), "*", 0x0, ""); + + nmb->question.question_type = 0x21; + nmb->question.question_class = 0x1; +} + +int build_nmb(char *buf, struct nmb_packet *nmb) +{ + unsigned char *ubuf = (unsigned char *)buf; + int offset=0; + + /* put in the header */ + RSSVAL(ubuf,offset, nmb->header.name_trn_id); + ubuf[offset+2] = (nmb->header.opcode & 0xF) << 3; + if (nmb->header.response) ubuf[offset+2] |= (1<<7); + if (nmb->header.nm_flags.authoritative && + nmb->header.response) ubuf[offset+2] |= 0x4; + if (nmb->header.nm_flags.trunc) ubuf[offset+2] |= 0x2; + if (nmb->header.nm_flags.recursion_desired) ubuf[offset+2] |= 0x1; + if (nmb->header.nm_flags.recursion_available && + nmb->header.response) ubuf[offset+3] |= 0x80; + if (nmb->header.nm_flags.bcast) ubuf[offset+3] |= 0x10; + ubuf[offset+3] |= (nmb->header.rcode & 0xF); + + RSSVAL(ubuf, offset+4, nmb->header.qdcount); + RSSVAL(ubuf, offset+6, nmb->header.ancount); + RSSVAL(ubuf, offset+8, nmb->header.nscount); + RSSVAL(ubuf, offset+10, nmb->header.arcount); + + offset += 12; + if (nmb->header.qdcount) { + /* XXXX this doesn't handle a qdcount of > 1 */ + offset += put_nmb_name((char *)ubuf, offset, &nmb->question.question_name); + RSSVAL(ubuf,offset, nmb->question.question_type); + RSSVAL(ubuf,offset+2, nmb->question.question_class); + offset += 4; + } + return offset; +} + +int parse_nmb(char *inbuf, int length, struct nmb_packet *nmb) +{ + int nm_flags, offset; + + memset((char *)nmb, 0, sizeof(*nmb)); + + if (length < 12) return(0); + + /* parse the header */ + nmb->header.name_trn_id = RSVAL(inbuf, 0); + + nmb->header.opcode = (CVAL(inbuf, 2) >> 3) & 0xF; + nmb->header.response = ((CVAL(inbuf, 2) >> 7) & 1) ? 1 : 0; + nm_flags = ((CVAL(inbuf, 2) & 0x7) << 4) + (CVAL(inbuf, 3) >> 4); + nmb->header.nm_flags.bcast = (nm_flags & 1) ? 1 : 0; + nmb->header.nm_flags.recursion_available = (nm_flags & 8) ? 1 : 0; + nmb->header.nm_flags.recursion_desired = (nm_flags & 0x10) ? 1 : 0; + nmb->header.nm_flags.trunc = (nm_flags & 0x20) ? 1 : 0; + nmb->header.nm_flags.authoritative = (nm_flags & 0x40) ? 1 : 0; + nmb->header.rcode = CVAL(inbuf, 3) & 0xF; + nmb->header.qdcount = RSVAL(inbuf, 4); + nmb->header.ancount = RSVAL(inbuf, 6); + nmb->header.nscount = RSVAL(inbuf, 8); + nmb->header.arcount = RSVAL(inbuf, 10); + + if (nmb->header.qdcount) { + offset = parse_nmb_name(inbuf, 12, length, &nmb->question.question_name); + if (!offset) return 0; + + if (length - (12+offset) < 4) return 0; + nmb->question.question_type = RSVAL(inbuf, 12+offset); + nmb->question.question_class = RSVAL(inbuf, 12+offset+2); + + offset += 12+4; + } else { + offset = 12; + } + + /* and any resource records */ + if (nmb->header.ancount && + !parse_alloc_res_rec(inbuf, &offset, length, &nmb->answers, + nmb->header.ancount)) { + return 0; + } + + if (nmb->header.nscount && + !parse_alloc_res_rec(inbuf, &offset, length, &nmb->nsrecs, + nmb->header.nscount)) { + return 0; + } + + if (nmb->header.arcount && + !parse_alloc_res_rec(inbuf, &offset, length, &nmb->additional, + nmb->header.arcount)) { + return 0; + } + + return 1; +} + +void make_nmb_name(struct nmb_name *n, const char *name, int type, const char *this_scope) +{ + memset((char *)n, 0, sizeof(struct nmb_name)); + strncpy(n->name, name, 15); + strupper(n->name); + n->name_type = (unsigned int)type & 0xFF; + strncpy(n->scope, this_scope, 63); + strupper(n->scope); +} + +int parse_nmb_name(char *inbuf, int offset, int length, struct nmb_name *name) +{ + int m, n = 0; + unsigned char *ubuf = (unsigned char *)inbuf; + int ret = 0; + int got_pointer = 0; + int loop_count = 0; + + if (length - offset < 2) + return 0; + + /* handle initial name pointers */ + if (!handle_name_ptrs(ubuf, &offset, length, &got_pointer, &ret)) + return 0; + + m = ubuf[offset]; + + if (!m) + return 0; + if ((m & 0xC0) || offset+m+2 > length) + return 0; + + memset((char *)name, 0, sizeof(*name)); + + /* the "compressed" part */ + if (!got_pointer) + ret += m + 2; + offset++; + + while (m > 0) { + unsigned char c1,c2; + c1 = ubuf[offset++]-'A'; + c2 = ubuf[offset++]-'A'; + if ((c1 & 0xF0) || (c2 & 0xF0) || (n > sizeof(name->name)-1)) + return 0; + name->name[n++] = (c1<<4) | c2; + m -= 2; + } + name->name[n] = 0; + + if (n==16) { + /* parse out the name type, + its always in the 16th byte of the name */ + name->name_type = ((unsigned char)name->name[15]) & 0xff; + + /* remove trailing spaces */ + name->name[15] = 0; + n = 14; + while (n && name->name[n]==' ') + name->name[n--] = 0; + } + + /* now the domain parts (if any) */ + n = 0; + while (ubuf[offset]) { + /* we can have pointers within the domain part as well */ + if (!handle_name_ptrs(ubuf,&offset,length,&got_pointer,&ret)) + return 0; + + m = ubuf[offset]; + /* + * Don't allow null domain parts. + */ + if (!m) + return 0; + if (!got_pointer) + ret += m+1; + if (n) + name->scope[n++] = '.'; + if (m + 2 + offset > length || n + m + 1 > sizeof(name->scope)) + return 0; + offset++; + while (m--) + name->scope[n++] = (char)ubuf[offset++]; + + /* + * Watch for malicious loops. + */ + if (loop_count++ == 10) + return 0; + } + name->scope[n++] = 0; + + return ret; +} + +int put_nmb_name(char *buf, int offset, struct nmb_name *name) +{ + int ret,m; + char buf1[128]; + char *p; + + if (strcmp(name->name,"*") == 0) { + /* special case for wildcard name */ + memset(buf1,'\0',20); + buf1[0] = '*'; + buf1[15] = name->name_type; + } else { + snprintf(buf1, sizeof(buf1) - 1,"%-15.15s%c",name->name,name->name_type); + } + + buf[offset] = 0x20; + ret = 34; + + for (m=0; m<16; m++) { + buf[offset + 1 + 2*m] = 'A' + ((buf1[m] >> 4) & 0xF); + buf[offset + 2 + 2*m] = 'A' + ( buf1[m] & 0xF); + } + offset += 33; + + buf[offset] = 0; + + if (name->scope[0]) { + /* XXXX this scope handling needs testing */ + ret += strlen(name->scope) + 1; + strcpy(&buf[offset + 1], name->scope); + + p = &buf[offset + 1]; + while ((p = strchr(p, '.'))) { + buf[offset] = PTR_DIFF(p, &buf[offset]); + offset += buf[offset]; + p = &buf[offset+1]; + } + buf[offset] = strlen(&buf[offset+1]); + } + + return ret; +} + +int handle_name_ptrs(unsigned char *ubuf, int *offset, int length, + int *got_pointer, int *ret) +{ + int loop_count=0; + + while ((ubuf[*offset] & 0xC0) == 0xC0) { + if (!*got_pointer) (*ret) += 2; + (*got_pointer) = 1; + (*offset) = ((ubuf[*offset] & ~0xC0) << 8) | ubuf[(*offset)+1]; + if (loop_count++ == 10 || (*offset) < 0 || (*offset) > (length-2)) { + return 0; + } + } + return 1; +} + +int parse_alloc_res_rec(char *inbuf, int *offset, int length, + struct res_rec **recs, int count) +{ + int i; + *recs = (struct res_rec *)malloc(sizeof(**recs) * count); + if (!*recs) return 0; + + memset((char *)*recs, 0, sizeof(**recs) * count); + + for (i=0; i length) { + free(*recs); + *recs = NULL; + return 0; + } + (*recs)[i].rr_type = RSVAL(inbuf, (*offset)); + (*recs)[i].rr_class = RSVAL(inbuf, (*offset)+2); + (*recs)[i].ttl = RIVAL(inbuf, (*offset)+4); + (*recs)[i].rdlength = RSVAL(inbuf, (*offset)+8); + (*offset) += 10; + if ((*recs)[i].rdlength > sizeof((*recs)[i].rdata) || + (*offset)+(*recs)[i].rdlength > length) { + free(*recs); + *recs = NULL; + return 0; + } + memcpy((*recs)[i].rdata, inbuf+(*offset), (*recs)[i].rdlength); + (*offset) += (*recs)[i].rdlength; + } + return 0; +} + +void free_nmb_packet(struct nmb_packet *nmb) +{ + if (nmb->answers) { + free(nmb->answers); + nmb->answers = NULL; + } + if (nmb->nsrecs) { + free(nmb->nsrecs); + nmb->nsrecs = NULL; + } + if (nmb->additional) { + free(nmb->additional); + nmb->additional = NULL; + } + free(nmb); +} + diff --git a/nmb.h b/nmb.h new file mode 100644 index 0000000..5b4e569 --- /dev/null +++ b/nmb.h @@ -0,0 +1,42 @@ +/* + * nbtscanner -- a tool for scanning large networks for SMB servers. + * + * nmb.h: Prototypes for nmb.c. + * Copyright (C) 2000 Steinar H. Gunderson + * + * Large amounts of code adapted from Samba (http://www.samba.org/) + * Copyright (C) Andrew Tridgell 1994-1998, and others. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _NMB_H +#define _NMB_H 1 + +#include "packet.h" + +void build_nbt_packet(struct nmb_packet *nmb, int name_trn_id); +int put_nmb_name(char *buf, int offset, struct nmb_name *name); +int build_nmb(char *buf, struct nmb_packet *nmb); +int parse_nmb(char *inbuf, int length, struct nmb_packet *nmb); +void make_nmb_name(struct nmb_name *n, const char *name, int type, const char *this_scope); +int parse_nmb_name(char *inbuf,int offset,int length, struct nmb_name *name); +int handle_name_ptrs(unsigned char *ubuf, int *offset, int length, + int *got_pointer, int *ret); +int parse_alloc_res_rec(char *inbuf, int *offset, int length, + struct res_rec **recs, int count); +void free_nmb_packet(struct nmb_packet *nmb); + +#endif /* _NMB_H */ diff --git a/outputfile.c b/outputfile.c new file mode 100644 index 0000000..90efe58 --- /dev/null +++ b/outputfile.c @@ -0,0 +1,57 @@ +/* + * nbtscanner -- a tool for scanning large networks for SMB servers. + * + * outputfile.c: nbtscanner text file output. + * Copyright (C) 2000 Steinar H. Gunderson + * + * Large amounts of code adapted from Samba (http://www.samba.org/) + * Copyright (C) Andrew Tridgell 1994-1998, and others. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mysql_interface.h" +#include "configfile.h" + +int main(int argc, char *argv[]) +{ + parse_configfile(0); + + if (!use_mysql) { + if (verbosity >= 1) { + fprintf(stderr, "Eeeeh, you have disabled MySQL! :-)\n"); + } + exit(1); + } + + print_all_records_mysql(); + finish_mysql(); + + return 0; +} + +/* will never be called */ +void scan_range(struct in_addr ip, int rangesize) {} diff --git a/packet.h b/packet.h new file mode 100644 index 0000000..c7c889c --- /dev/null +++ b/packet.h @@ -0,0 +1,76 @@ +/* + * nbtscanner -- a tool for scanning large networks for SMB servers. + * + * packet.h: NMB/NBT packet structure definitions. + * Copyright (C) 2000 Steinar H. Gunderson + * + * Large amounts of code adapted from Samba (http://www.samba.org/) + * Copyright (C) Andrew Tridgell 1994-1998, and others. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _PACKET_H +#define _PACKET_H 1 + +#define MAX_DGRAM_SIZE 576 +#define MIN_DGRAM_SIZE 12 + +struct nmb_name { + char name[17]; + char scope[64]; + unsigned int name_type; +}; + +struct res_rec { + struct nmb_name rr_name; + int rr_type; + int rr_class; + int ttl; + int rdlength; + char rdata[MAX_DGRAM_SIZE]; +}; + +struct nmb_packet { + struct { + int name_trn_id; + int opcode; + int response; + struct { + int bcast; + int recursion_available; + int recursion_desired; + int trunc; + int authoritative; + } nm_flags; + int rcode; + int qdcount; + int ancount; + int nscount; + int arcount; + } header; + + struct { + struct nmb_name question_name; + int question_type; + int question_class; + } question; + + struct res_rec *answers; + struct res_rec *nsrecs; + struct res_rec *additional; +}; + +#endif /* _PACKET_H */ diff --git a/socket.c b/socket.c new file mode 100644 index 0000000..4252e48 --- /dev/null +++ b/socket.c @@ -0,0 +1,158 @@ +/* + * nbtscanner -- a tool for scanning large networks for SMB servers. + * + * socket.c: Most functions that are related to TCP/IP (socket) use. + * Copyright (C) 2000 Steinar H. Gunderson + * + * Large amounts of code adapted from Samba (http://www.samba.org/) + * Copyright (C) Andrew Tridgell 1994-1998, and others. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * This file is probably the most platform-dependent one, and would most + * likely be needed to undergo some changes if ported to another OS than + * the ones using BSD-style sockets (Winsock is a variant of these, + * by the way -- you may only want to change some header files and add some + * extra initialization calls). + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "socket.h" +#include "nmb.h" +#include "packet.h" + +int open_sockets(void) +{ + unsigned int one = 1; + struct sockaddr_in sin; + int sock; + + memset((char *)&sin, 0, sizeof(sin)); + sin.sin_port = htons(0); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = INADDR_ANY; + + sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sock == -1) { + perror("socket()"); + exit(0); + } + + setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one)); + + /* bind the socket */ + if (bind(sock, (struct sockaddr *) &sin,sizeof(sin)) < 0) { + perror("bind()"); + exit(1); + } + + return sock; +} + +int send_packet(struct nmb_packet *nmb, struct in_addr ip, int port, int fd) +{ + char buf[1024]; + int len = 0; + + memset(buf, 0, sizeof(buf)); + + len = build_nmb(buf,nmb); + if (!len) return(0); + + return(send_udp(fd,buf,len,ip,port)); +} + +struct nmb_packet *receive_packet(int fd, int t, struct in_addr *in) +{ + fd_set fds; + struct timeval timeout; + + FD_ZERO(&fds); + FD_SET(fd,&fds); + timeout.tv_sec = t / 1000; + timeout.tv_usec = 1000 * (t % 1000); + + select(fd+1,&fds,NULL,NULL,&timeout); + + if (FD_ISSET(fd,&fds)) + return read_packet(fd, in); + + return(NULL); +} + +struct nmb_packet *read_packet(int fd, struct in_addr *in) +{ + /* extern struct in_addr lastip; + extern int lastport; */ + char buf[MAX_DGRAM_SIZE]; + int length; + int ok = 0; + struct nmb_packet *nmb; + + length = read_udp_socket(fd, buf, sizeof(buf), in); + if (length < MIN_DGRAM_SIZE) return(NULL); + + nmb = (struct nmb_packet *)malloc(sizeof(struct nmb_packet)); /* ?? */ + ok = parse_nmb(buf, length, nmb); + + return(nmb); +} + +int send_udp(int fd,char *buf,int len,struct in_addr ip,int port) +{ + int ret; + struct sockaddr_in sock_out; + + /* set the address and port */ + memset((char *)&sock_out, 0, sizeof(sock_out)); + memcpy((char *)&sock_out.sin_addr, (char *)&ip, 4); + sock_out.sin_port = htons(port); + sock_out.sin_family = AF_INET; + + ret = (sendto(fd,buf,len,0,(struct sockaddr *)&sock_out, + sizeof(sock_out)) >= 0); + + return ret; +} + +ssize_t read_udp_socket(int fd, char *buf, size_t len, struct in_addr *in) +{ + ssize_t ret; + struct sockaddr_in sin; + int sin_len; + + sin_len = sizeof(sin); + memset((char *)&sin, 0, sin_len); + ret = (ssize_t)recvfrom(fd, buf, len, 0, (struct sockaddr *)&sin, &sin_len); + if (ret <= 0) { + perror("recvfrom()"); + return(0); + } + + *in = sin.sin_addr; + + return ret; +} + + diff --git a/socket.h b/socket.h new file mode 100644 index 0000000..2e21dc1 --- /dev/null +++ b/socket.h @@ -0,0 +1,39 @@ +/* + * nbtscanner -- a tool for scanning large networks for SMB servers. + * + * socket.h: Prototypes for socket.c. + * Copyright (C) 2000 Steinar H. Gunderson + * + * Large amounts of code adapted from Samba (http://www.samba.org/) + * Copyright (C) Andrew Tridgell 1994-1998, and others. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _SOCKET_H +#define _SOCKET_H 1 + +#include "packet.h" + +#include + +int open_sockets(void); +int send_packet(struct nmb_packet *nmb, struct in_addr ip, int port, int fd); +struct nmb_packet *receive_packet(int fd, int t, struct in_addr *in); +struct nmb_packet *read_packet(int fd, struct in_addr *in); +int send_udp(int fd, char *buf, int len, struct in_addr ip, int port); +ssize_t read_udp_socket(int fd, char *buf, size_t len, struct in_addr *in); + +#endif /* _SOCKET_H */ diff --git a/stats.c b/stats.c new file mode 100644 index 0000000..925d62c --- /dev/null +++ b/stats.c @@ -0,0 +1,68 @@ +/* + * nbtscanner -- a tool for scanning large networks for SMB servers. + * + * stats.c: Running statistics. + * Copyright (C) 2000 Steinar H. Gunderson + * + * Large amounts of code adapted from Samba (http://www.samba.org/) + * Copyright (C) Andrew Tridgell 1994-1998, and others. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "stats.h" +#include "configfile.h" +#include "util.h" + +#include +#include + +int num_recv; +int num_recv_retries; +int num_failed; +int num_sent; +int num_sent_total; +enum statuses status; + +struct timeval last_stats; + +void init_stats() +{ + num_recv = 0; + num_recv_retries = 0; + num_failed = 0; + num_sent = 0; + num_sent_total = 0; + status = SCANNING; + + gettimeofday(&last_stats, NULL); +} + +void print_stats(int force) +{ + struct timeval now; + + gettimeofday(&now, NULL); + if (verbosity >= 3 && (mydifftime(last_stats, now) > 1000 || force == 1)) { + fprintf(stderr, "%s: Received %5u/%5u/%5u (%5u failed) (avg. " + "retries/succ.: %3.2f)\r", + (status == SCANNING) ? "Scanning" : "Retrying", + num_recv, num_sent, num_sent_total, num_failed, + (float)num_recv_retries / (float)num_recv); + + gettimeofday(&last_stats, NULL); + } +} + diff --git a/stats.h b/stats.h new file mode 100644 index 0000000..4723a1d --- /dev/null +++ b/stats.h @@ -0,0 +1,44 @@ +/* + * nbtscanner -- a tool for scanning large networks for SMB servers. + * + * stats.h: Definitions and prototypes for stats.c. + * Copyright (C) 2000 Steinar H. Gunderson + * + * Large amounts of code adapted from Samba (http://www.samba.org/) + * Copyright (C) Andrew Tridgell 1994-1998, and others. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _STATS_H +#define _STATS_H 1 + +extern int num_recv; +extern int num_recv_retries; +extern int num_failed; +extern int num_sent; +extern int num_sent_total; + +enum statuses { + SCANNING, + RETRYING +}; + +extern enum statuses status; + +void init_stats(); +void print_stats(int force); + +#endif /* _STATS_H */ diff --git a/util.c b/util.c new file mode 100644 index 0000000..9b476cf --- /dev/null +++ b/util.c @@ -0,0 +1,38 @@ +/* + * nbtscanner -- a tool for scanning large networks for SMB servers. + * + * util.c: Useful small functions. + * Copyright (C) 2000 Steinar H. Gunderson + * + * Large amounts of code adapted from Samba (http://www.samba.org/) + * Copyright (C) Andrew Tridgell 1994-1998, and others. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include + +void strupper(char *s) +{ + while (*s) { *s = toupper(*s); s++; } +} + +int mydifftime(struct timeval t1, struct timeval t2) +{ + return (t2.tv_sec - t1.tv_sec) * 1000 + + (t2.tv_usec - t1.tv_usec) / 1000; +} + diff --git a/util.h b/util.h new file mode 100644 index 0000000..2af4e9d --- /dev/null +++ b/util.h @@ -0,0 +1,33 @@ +/* + * nbtscanner -- a tool for scanning large networks for SMB servers. + * + * string_util.h: Function prototypes for string_util.c. + * Copyright (C) 2000 Steinar H. Gunderson + * + * Large amounts of code adapted from Samba (http://www.samba.org/) + * Copyright (C) Andrew Tridgell 1994-1998, and others. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _STRING_UTIL_H +#define _STRING_UTIL_H 1 + +#include + +void strupper(char *s); +int mydifftime(struct timeval t1, struct timeval t2); + +#endif /* STRING_UTIL_H */