]> git.sesse.net Git - nbtscanner/commitdiff
Import nbtscanner 0.1.0.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Thu, 18 Apr 2019 15:25:39 +0000 (17:25 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Thu, 18 Apr 2019 15:25:39 +0000 (17:25 +0200)
24 files changed:
COPYING [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
byteorder.h [new file with mode: 0644]
configfile.c [new file with mode: 0644]
configfile.h [new file with mode: 0644]
id_list.c [new file with mode: 0644]
id_list.h [new file with mode: 0644]
init.sql [new file with mode: 0644]
mysql_interface.c [new file with mode: 0644]
mysql_interface.h [new file with mode: 0644]
nbtscanner.c [new file with mode: 0644]
nbtscanner.conf [new file with mode: 0644]
nbtscanner.h [new file with mode: 0644]
nmb.c [new file with mode: 0644]
nmb.h [new file with mode: 0644]
outputfile.c [new file with mode: 0644]
packet.h [new file with mode: 0644]
socket.c [new file with mode: 0644]
socket.h [new file with mode: 0644]
stats.c [new file with mode: 0644]
stats.h [new file with mode: 0644]
util.c [new file with mode: 0644]
util.h [new file with mode: 0644]

diff --git a/COPYING b/COPYING
new file mode 100644 (file)
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.
+\f
+                   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.)
+\f
+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.
+\f
+  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.
+\f
+  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
+\f
+           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.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    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.
+
+  <signature of Ty Coon>, 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 (file)
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 (file)
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 <sgunderson@bigfoot.com>
diff --git a/byteorder.h b/byteorder.h
new file mode 100644 (file)
index 0000000..e90b3d7
--- /dev/null
@@ -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 (file)
index 0000000..3b15403
--- /dev/null
@@ -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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+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 (file)
index 0000000..767d4be
--- /dev/null
@@ -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 (file)
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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+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 (file)
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 <sys/time.h>
+#include <netinet/in.h>
+
+/* 
+ * 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 (file)
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 (file)
index 0000000..c51633a
--- /dev/null
@@ -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 <stdio.h>
+#include <stdlib.h>
+#include <mysql.h>
+
+#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 (file)
index 0000000..26565dc
--- /dev/null
@@ -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 (file)
index 0000000..a7c5e25
--- /dev/null
@@ -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 <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+
+#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;
+                       }
+               }
+
+               /* <ACTIVE>, non-<GROUP> server hostname (type 0x00) */ 
+               if ((p[0] & 0x80) == 0x00 && ((p[0] & 0x1f) == 0x04) && type == 0x00) {
+                       strcpy(hostname, qname);
+               }
+               /* <ACTIVE>, non-<GROUP> server hostname (type 0x20) */ 
+               if ((p[0] & 0x80) == 0x00 && ((p[0] & 0x1f) == 0x04) && type == 0x20) {
+                       strcpy(fileservername, qname);
+               }
+               /* <ACTIVE>, <GROUP> 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<argc;i++) {
+               struct in_addr ip;
+
+               ip.s_addr = inet_addr(argv[i]); //interpret_addr2(argv[i]);
+               send_nbt_packet(fd, ip);
+               recv_nbt_packets(fd);
+       } */
+
+       /*
+        * receive answers and resend packets until all answers have
+        * been received, or all packets have been timed out
+        */
+       status = RETRYING;
+       while (get_num_free_ids() != 65536) {
+               recv_nbt_packets(fd);
+               resend_timed_out_packets(fd);
+       }
+
+       if (use_mysql) {
+               finish_mysql();
+       }
+
+       if (verbosity >= 3) {
+               print_stats(1);
+               fprintf(stderr, "\n");
+       }
+
+       return 0;
+}
diff --git a/nbtscanner.conf b/nbtscanner.conf
new file mode 100644 (file)
index 0000000..06da5e7
--- /dev/null
@@ -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 (file)
index 0000000..991bf45
--- /dev/null
@@ -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 <netinet/in.h>
+
+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 (file)
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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#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<count; i++) {
+               int l = parse_nmb_name(inbuf, *offset, length, &(*recs)[i].rr_name);
+               (*offset) += l;
+               if (!l || (*offset)+10 > 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 (file)
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 (file)
index 0000000..90efe58
--- /dev/null
@@ -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 <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+
+#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 (file)
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 (file)
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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#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 (file)
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 <netinet/in.h>
+
+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 (file)
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 <stdio.h>
+#include <sys/time.h>
+
+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 (file)
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 (file)
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 <ctype.h>
+#include <sys/time.h>
+
+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 (file)
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 <sys/time.h>
+
+void strupper(char *s);
+int mydifftime(struct timeval t1, struct timeval t2);
+
+#endif /* STRING_UTIL_H */