diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 07:42:04 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 07:42:04 +0000 |
commit | 0d47952611198ef6b1163f366dc03922d20b1475 (patch) | |
tree | 3d840a3b8c0daef0754707bfb9f5e873b6b1ac13 /zenmap/radialnet | |
parent | Initial commit. (diff) | |
download | nmap-upstream.tar.xz nmap-upstream.zip |
Adding upstream version 7.94+git20230807.3be01efb1+dfsg.upstream/7.94+git20230807.3be01efb1+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'zenmap/radialnet')
38 files changed, 9304 insertions, 0 deletions
diff --git a/zenmap/radialnet/CHANGELOG b/zenmap/radialnet/CHANGELOG new file mode 100644 index 0000000..cb2c4af --- /dev/null +++ b/zenmap/radialnet/CHANGELOG @@ -0,0 +1,149 @@ +RadialNet 0.44 +-------------- + +o Fix bug caused by gtk.gdk.PixbufLoader that don't recognize image type in + Windows. Now gtk.gdk.pixbuf_new_from_file() is used (thanks to IndianZ). + +o Added new version of XMLTreeParser.py called XMLHandler.py. + +o Added new version of bestwidgets. + +o Change radialnet.py file name to radialnet.pyw to application starts with no + command prompt on Windows. + + +RadialNet 0.43 +-------------- + +o Clean __init__.py files. + +o Added vendor to address field when addrtype is MAC. + +o Added new version of bestwidgets. + +o Fixed bug caused by list key error on NodeNotebook.py. + + +RadialNet 0.42 +-------------- + +o Fixed bug caused when tcptssequence xml node has no values information. + +o Improve the coherence in animation. + + +RadialNet 0.41 +-------------- + +o Create a solution to fix the gtk issue that don't show text in BWTextEditor + class correctly (thanks to Luís Bastião). + +o Due to encoding problems the encoding of all file was changed to utf-8. + +o Created a new logo and About dialog. New logo was used as window icon too. + +o Added a Info module that contains the program information. + +o Added a Image superclass in gui/Icons.py file. Change gui/Icons.py filename to + gui/Image.py. + +o Added a Path class to hold directory base. This make possible RadialNet + runnable from any directory. + + +RadialNet 0.4 +------------- + +o Incorporated a HostsViewer class that lists the hosts in a left list and show + its information in a NodeNotebook in the right side. It can be accessed in the + new Tools button on toolbar. + +o Added a complete OS Fingerprint and Sequences view with other general + informations in the NodeNotebook class. + +o Create a set of class to make more easy follow the Gnome HIG 2.0 + specifications and the creation of complex composed widgets. This set is + called bestwidgets. + +o Create a class and file named NodeNotebook and move node noetebook pages to + it. + +o Added a Application class to solve user interface issues like hide and show of + widgets. + +o Improve command line options with ArgvHandle class. And add a file chooser + dialog to interface to open Nmap XML files from the GUI. + +o Enable visualization of host with no traceroute information. These nodes are + link to localhost and has black dashed connections. This make possible for + non-privileged users use the RadialNet. + +o Remove statusbar from node's window and put hostname in title. + +o Added a new notebook to node's window with all traceroute information. + +o By default latency numbers are hidden, ring gap is changed to 30 and fisheye + spread factor to 0.5. + +o Convert frames in control panel to expanders to grant to user see only he + need. + +o Move actions toolbar menu to right control panel. And a information button + was added. They are placed in a "Action" expander. + +o Include "Option" expander in "View" expander. + + +RadialNet 0.31 +-------------- + +o Improve the animation by coherent calculus of children positions. Using some + angle conditions we can perform a better animation. + +o Reduce excessive processing on some update methods that check values in + RadialNet class periodically. + + +RadialNet 0.3 +------------- + +o New services viewer on pop-up windows. With NSE script output support with a + text viewer. + +o Clean the interface hiding some controllers if no needed using toggle buttons. + +o Added option to enable/disable slow-in/slow-out animation in options list. + +o Fixes wrong English messages in the program (thanks to DePriest, Jasey). + + +RadialNet 0.2 +------------- + +o Improve icons apparency, size and position. + +o Added latency mean for each edge as text and width of edge. The edge's width + is normalized between 1 (min value) to 5 (max value) pixels. + +o When a node is a group we draw a black circle if localhost (127.0.0.1) is + grouped on it. + +o Change mouse button events to a toolbar. The options. We include buttons to + guide mouse actions. Three options are added, one to change the center of + visualization, another to group node's children, and more one to fill node's + draw region. + +o Added region fill feature. When clicking in a node with this option the + hierarchical region that a node use to draw its children is filled with a + chosen color (red, yellow or green). + +o Added different draw properties for unknown nodes and edges latencies. If a + node is unknown we draw a white node with blue stroke, and if the edge latency + is unknown we draw it dashed. + +o Decrease draw complexity. Reducing the number of draw method and making the + methods for draw node and edges more intelligent. + +o Fixed division by zero error when number of frames is less than 3. This + happens because the interpolation method need a number of pass great or equal + to 3 (thanks to Hiroshi). diff --git a/zenmap/radialnet/README b/zenmap/radialnet/README new file mode 100644 index 0000000..54d1a7a --- /dev/null +++ b/zenmap/radialnet/README @@ -0,0 +1,10 @@ +To start the application you may just double-click the radialnet.py file or +start it with the following command: + + $ python radialnet.py + +To view command line list of arguments type '--help': + + $ python radialnet.py --help + +Att, João Medeiros <ignotus21@gmail.com>. diff --git a/zenmap/radialnet/__init__.py b/zenmap/radialnet/__init__.py new file mode 100644 index 0000000..98e2c1e --- /dev/null +++ b/zenmap/radialnet/__init__.py @@ -0,0 +1,58 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +__all__ = ["bestwidgets", "core", "gui", "util"] diff --git a/zenmap/radialnet/bestwidgets/__init__.py b/zenmap/radialnet/bestwidgets/__init__.py new file mode 100644 index 0000000..03877f0 --- /dev/null +++ b/zenmap/radialnet/bestwidgets/__init__.py @@ -0,0 +1,72 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk + +gtk_version_major, gtk_version_minor, gtk_version_release = gi.version_info + +#from boxes import BWHBox, BWVBox, BWTable, BWStatusbar, BWScrolledWindow +#from buttons import BWStockButton, BWToggleStockButton +#from comboboxes import BWChangeableComboBoxEntry +#from expanders import BWExpander +#from frames import BWFrame +#from labels import BWLabel, BWSectionLabel +#from textview import BWTextView, BWTextEditor +#from windows import BWWindow, BWMainWindow, BWAlertDialog diff --git a/zenmap/radialnet/bestwidgets/boxes.py b/zenmap/radialnet/bestwidgets/boxes.py new file mode 100644 index 0000000..5b43a90 --- /dev/null +++ b/zenmap/radialnet/bestwidgets/boxes.py @@ -0,0 +1,202 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk + +__all__ = ('BWBox', 'BWHBox', 'BWVBox', + 'BWStatusbar', 'BWTable', 'BWScrolledWindow') + + +class BWBox(Gtk.Box): + """ + """ + def bw_pack_start_expand_fill(self, widget, padding=0): + """ + """ + self.pack_start(widget, True, True, padding) + + def bw_pack_start_expand_nofill(self, widget, padding=0): + """ + """ + self.pack_start(widget, True, False, padding) + + def bw_pack_start_noexpand_nofill(self, widget, padding=0): + """ + """ + self.pack_start(widget, False, False, padding) + + def bw_pack_end_expand_fill(self, widget, padding=0): + """ + """ + self.pack_end(widget, True, True, padding) + + def bw_pack_end_expand_nofill(self, widget, padding=0): + """ + """ + self.pack_end(widget, True, False, padding) + + def bw_pack_end_noexpand_nofill(self, widget, padding=0): + """ + """ + self.pack_end(widget, False, False, padding) + + +class BWHBox(BWBox): + """ + """ + def __init__(self, homogeneous=False, spacing=12): + """ + """ + Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL, + homogeneous=homogeneous, spacing=spacing) + + +class BWVBox(BWBox): + """ + """ + def __init__(self, homogeneous=False, spacing=12): + """ + """ + Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL, + homogeneous=homogeneous, spacing=spacing) + + +class BWStatusbar(Gtk.Statusbar, BWBox): + """ + """ + def __init__(self, homogeneous=False, spacing=12): + """ + """ + Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL, + homogeneous=homogeneous, spacing=spacing) + + +class BWTable(Gtk.Table, BWBox): + """ + """ + def __init__(self, rows=1, columns=1, homogeneous=False): + """ + """ + Gtk.Table.__init__(self, n_rows=rows, n_columns=columns, + homogeneous=homogeneous) + self.bw_set_spacing(12) + + self.__rows = rows + self.__columns = columns + + self.__last_point = (0, 0) + + def bw_set_spacing(self, spacing): + """ + """ + self.set_row_spacings(spacing) + self.set_col_spacings(spacing) + + def bw_resize(self, rows, columns): + """ + """ + self.__rows = rows + self.__columns = columns + + self.resize(rows, columns) + + def bw_attach_next(self, + child, + xoptions=Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, + yoptions=Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, + xpadding=0, + ypadding=0): + """ + """ + row, column = self.__last_point + + if row != self.__rows: + + self.attach(child, + column, + column + 1, + row, + row + 1, + xoptions, + yoptions, + xpadding, + ypadding) + + if column + 1 == self.__columns: + + column = 0 + row += 1 + + else: + column += 1 + + self.__last_point = (row, column) + + +class BWScrolledWindow(Gtk.ScrolledWindow): + """ + """ + def __init__(self): + """ + """ + Gtk.ScrolledWindow.__init__(self) + self.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) + self.set_shadow_type(Gtk.ShadowType.NONE) + self.set_border_width(6) diff --git a/zenmap/radialnet/bestwidgets/buttons.py b/zenmap/radialnet/bestwidgets/buttons.py new file mode 100644 index 0000000..3d3239d --- /dev/null +++ b/zenmap/radialnet/bestwidgets/buttons.py @@ -0,0 +1,91 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk + + +class BWStockButton(Gtk.Button): + """ + """ + def __init__(self, stock, text=None, size=Gtk.IconSize.BUTTON): + """ + """ + Gtk.Button.__init__(self, label=text) + + self.__size = size + + self.__image = Gtk.Image() + self.__image.set_from_stock(stock, self.__size) + self.set_image(self.__image) + + +class BWToggleStockButton(Gtk.ToggleButton): + """ + """ + def __init__(self, stock, text=None, size=Gtk.IconSize.BUTTON): + """ + """ + Gtk.ToggleButton.__init__(self, label=text) + + self.__size = size + + self.__image = Gtk.Image() + self.__image.set_from_stock(stock, self.__size) + self.set_image(self.__image) diff --git a/zenmap/radialnet/bestwidgets/comboboxes.py b/zenmap/radialnet/bestwidgets/comboboxes.py new file mode 100644 index 0000000..e10d7e6 --- /dev/null +++ b/zenmap/radialnet/bestwidgets/comboboxes.py @@ -0,0 +1,135 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk, GObject + + +class BWChangeableComboBoxEntry(Gtk.ComboBoxText): + """ + """ + def __init__(self): + """ + """ + self.__liststore = Gtk.ListStore.new([str]) + + Gtk.ComboBoxText.__init__(self, model=self.__liststore, has_entry=True) + + self.connect("changed", self.__changed) + self.get_child().connect("changed", self.__entry_changed) + + self.__last_active = None + + def __changed(self, widget): + """ + """ + if self.get_active() != -1: + self.__last_active = self.get_active() + + def bw_get_length(self): + """ + """ + return len(self.__liststore) + + def __entry_changed(self, widget): + """ + """ + if len(self.__liststore) > 0 and\ + self.__last_active is not None and\ + self.get_active() == -1: + + iter = self.get_model().get_iter((self.__last_active,)) + self.__liststore.set_value(iter, 0, widget.get_text().strip()) + + def bw_get_active(self): + """ + """ + if self.get_active() == -1: + return self.__last_active + + return self.get_active() + + +# testing widget +if __name__ == "__main__": + + def button_clicked(widget, combo): + """ + """ + combo.append_text('New') + + window = Gtk.Window() + window.connect("destroy", lambda w: Gtk.main_quit()) + + box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0) + + combo = BWChangeableComboBoxEntry() + combo.append_text('New') + combo.set_active(0) + + button = Gtk.Button.new_with_label('More') + button.connect("clicked", button_clicked, combo) + + box.pack_start(button, False, False, 0) + box.pack_start(combo, True, True, 0) + + window.add(box) + window.show_all() + + Gtk.main() diff --git a/zenmap/radialnet/bestwidgets/expanders.py b/zenmap/radialnet/bestwidgets/expanders.py new file mode 100644 index 0000000..a89e08b --- /dev/null +++ b/zenmap/radialnet/bestwidgets/expanders.py @@ -0,0 +1,97 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk +from radialnet.bestwidgets.labels import BWSectionLabel + + +class BWExpander(Gtk.Expander): + """ + """ + def __init__(self, label=''): + """ + """ + Gtk.Expander.__init__(self) + + self.__label = BWSectionLabel(label) + self.set_label_widget(self.__label) + + self.__alignment = Gtk.Alignment.new(0, 0, 1, 1) + self.__alignment.set_padding(12, 0, 24, 0) + + self.add(self.__alignment) + + def bw_set_label_text(self, text): + """ + """ + self.__label.bw_set_text(text) + + def bw_add(self, widget): + """ + """ + if len(self.__alignment.get_children()) > 0: + self.__alignment.remove(self.__alignment.get_children()[0]) + + self.__alignment.add(widget) + + def bw_no_padding(self): + """ + """ + self.__alignment.set_padding(0, 0, 0, 0) diff --git a/zenmap/radialnet/bestwidgets/frames.py b/zenmap/radialnet/bestwidgets/frames.py new file mode 100644 index 0000000..3a35021 --- /dev/null +++ b/zenmap/radialnet/bestwidgets/frames.py @@ -0,0 +1,96 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk, Gdk + + +class BWFrame(Gtk.Frame): + """ + """ + def __init__(self, label=''): + """ + """ + Gtk.Frame.__init__(self) + + self.set_border_width(3) + self.set_shadow_type(Gtk.ShadowType.NONE) + + self.__alignment = Gtk.Alignment.new(0, 0, 1, 1) + self.__alignment.set_padding(12, 0, 24, 0) + + self.add(self.__alignment) + + self.bw_set_label(label) + + def bw_set_label(self, label): + """ + """ + self.set_label("<b>" + label + "</b>") + self.get_label_widget().set_use_markup(True) + + def bw_add(self, widget): + """ + """ + self.__alignment.add(widget) + + def bw_remove(self, widget): + """ + """ + self.__alignment.remove(widget) diff --git a/zenmap/radialnet/bestwidgets/labels.py b/zenmap/radialnet/bestwidgets/labels.py new file mode 100644 index 0000000..c3ec94f --- /dev/null +++ b/zenmap/radialnet/bestwidgets/labels.py @@ -0,0 +1,94 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk + + +class BWLabel(Gtk.Label): + """ + """ + def __init__(self, text=''): + """ + """ + Gtk.Label.__init__(self) + + self.set_text(text) + self.set_justify(Gtk.Justification.LEFT) + self.set_alignment(0, 0.50) + self.set_line_wrap(True) + + +class BWSectionLabel(Gtk.Label): + """ + """ + def __init__(self, text=''): + """ + """ + Gtk.Label.__init__(self) + + self.set_markup('<b>' + text + '</b>') + self.set_justify(Gtk.Justification.LEFT) + self.set_alignment(0, 0.50) + self.set_line_wrap(True) + + def bw_set_text(self, text): + """ + """ + self.set_markup('<b>' + text + '</b>') diff --git a/zenmap/radialnet/bestwidgets/textview.py b/zenmap/radialnet/bestwidgets/textview.py new file mode 100644 index 0000000..9deda93 --- /dev/null +++ b/zenmap/radialnet/bestwidgets/textview.py @@ -0,0 +1,209 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk +from radialnet.bestwidgets.boxes import * + + +class BWTextView(BWScrolledWindow): + """ + """ + def __init__(self): + """ + """ + BWScrolledWindow.__init__(self) + + self.__auto_scroll = False + + self.__create_widgets() + + def __create_widgets(self): + """ + """ + self.__textbuffer = Gtk.TextBuffer() + self.__textview = Gtk.TextView.new_with_buffer(self.__textbuffer) + + self.add_with_viewport(self.__textview) + + def bw_set_auto_scroll(self, value): + """ + """ + self.__auto_scroll = value + + def bw_set_editable(self, editable): + """ + """ + self.__textview.set_editable(False) + + def bw_modify_font(self, font): + """ + """ + self.__textview.modify_font(font) + + def bw_set_text(self, text): + """ + """ + self.__textbuffer.set_text(text) + + if self.__auto_scroll: + self.bw_set_scroll_down() + + def bw_get_text(self): + """ + """ + return self.__textbuffer.get_text(self.__textbuffer.get_start_iter(), + self.__textbuffer.get_end_iter()) + + def bw_set_scroll_down(self): + """ + """ + self.get_vadjustment().set_value(self.get_vadjustment().upper) + + def bw_get_textbuffer(self): + """ + """ + return self.__textbuffer + + +class BWTextEditor(BWScrolledWindow): + """ + """ + def __init__(self): + """ + """ + BWScrolledWindow.__init__(self) + self.connect('draw', self.__draw) + + self.__auto_scroll = False + + self.__create_widgets() + + def __create_widgets(self): + """ + """ + self.__hbox = BWHBox(spacing=6) + + self.__textbuffer = Gtk.TextBuffer() + self.__textview = Gtk.TextView.new_with_buffer(self.__textbuffer) + + self.__linebuffer = Gtk.TextBuffer() + self.__lineview = Gtk.TextView.new_with_buffer(self.__linebuffer) + self.__lineview.set_justification(Gtk.Justification.RIGHT) + self.__lineview.set_editable(False) + self.__lineview.set_sensitive(False) + + self.__hbox.bw_pack_start_noexpand_nofill(self.__lineview) + self.__hbox.bw_pack_start_expand_fill(self.__textview) + + self.add_with_viewport(self.__hbox) + + def __draw(self, widget, event): + """ + """ + # code to fix a gtk issue that don't show text correctly + self.__hbox.check_resize() + + def bw_set_auto_scroll(self, value): + """ + """ + self.__auto_scroll = value + + def bw_set_editable(self, editable): + """ + """ + self.__textview.set_editable(False) + + def bw_modify_font(self, font): + """ + """ + self.__textview.modify_font(font) + self.__lineview.modify_font(font) + + def bw_set_text(self, text): + """ + """ + if text != "": + + count = text.count('\n') + text.count('\r') + + lines = range(1, count + 2) + lines = [str(i).strip() for i in lines] + + self.__textbuffer.set_text(text) + self.__linebuffer.set_text('\n'.join(lines)) + + if self.__auto_scroll: + self.bw_set_scroll_down() + + else: + + self.__textbuffer.set_text("") + self.__linebuffer.set_text("") + + def bw_get_text(self): + """ + """ + return self.__textbuffer.get_text(self.__textbuffer.get_start_iter(), + self.__textbuffer.get_end_iter()) + + def bw_set_scroll_down(self): + """ + """ + self.get_vadjustment().set_value(self.get_vadjustment().upper) diff --git a/zenmap/radialnet/bestwidgets/windows.py b/zenmap/radialnet/bestwidgets/windows.py new file mode 100644 index 0000000..fe61162 --- /dev/null +++ b/zenmap/radialnet/bestwidgets/windows.py @@ -0,0 +1,103 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk + +PRIMARY_TEXT_MARKUP = '<span weight="bold" size="larger">%s</span>' + + +class BWAlertDialog(Gtk.MessageDialog): + """ + """ + def __init__(self, parent=None, flags=0, type=Gtk.MessageType.INFO, + buttons=Gtk.ButtonsType.OK, + primary_text=None, + secondary_text=None): + + Gtk.MessageDialog.__init__(self, parent=parent, flags=flags, + message_type=type, buttons=buttons) + + self.connect('response', self.__destroy) + + self.set_resizable(False) + + self.set_title(_("Alert")) + self.set_markup(PRIMARY_TEXT_MARKUP % primary_text) + + if secondary_text: + self.format_secondary_text(secondary_text) + + def __destroy(self, dialog, id): + """ + """ + self.destroy() + + +class BWWindow(Gtk.Window): + """ + """ + def __init__(self, type=Gtk.WindowType.TOPLEVEL): + """ + """ + Gtk.Window.__init__(self, type=type) + self.set_border_width(5) + + +BWMainWindow = Gtk.Window diff --git a/zenmap/radialnet/core/ArgvHandle.py b/zenmap/radialnet/core/ArgvHandle.py new file mode 100644 index 0000000..2e72d93 --- /dev/null +++ b/zenmap/radialnet/core/ArgvHandle.py @@ -0,0 +1,98 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +import sys + + +class ArgvHandle: + """ + """ + def __init__(self, argv): + """ + """ + self.__argv = argv + + def get_option(self, option): + """ + """ + if option in self.__argv: + + index = self.__argv.index(option) + + if index + 1 < len(self.__argv): + return self.__argv[index + 1] + + return None + + def has_option(self, option): + """ + """ + return option in self.__argv + + def get_last_value(self): + """ + """ + return self.__argv[-1] + + +if __name__ == '__main__': + + import sys + + h = ArgvHandle(sys.argv) + + print(h.get_last_value()) diff --git a/zenmap/radialnet/core/Coordinate.py b/zenmap/radialnet/core/Coordinate.py new file mode 100644 index 0000000..5c82212 --- /dev/null +++ b/zenmap/radialnet/core/Coordinate.py @@ -0,0 +1,208 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +import math + + +class PolarCoordinate: + """ + Class to implement a polar coordinate object + """ + + def __init__(self, r=0, t=0): + """ + Constructor method of PolarCoordinate class + @type r: number + @param r: The radius of coordinate + @type t: number + @param t: The angle (theta) of coordinate in radians + """ + + self.__r = r + """Radius of polar coordinate""" + self.__t = t + """Angle (theta) of polar coordinate in radians""" + + def get_theta(self): + """ + """ + return math.degrees(self.__t) + + def get_radius(self): + """ + """ + return self.__r + + def set_theta(self, t): + """ + """ + self.__t = math.radians(t) + + def set_radius(self, r): + """ + """ + self.__r = r + + def get_coordinate(self): + """ + Set polar coordinate + @rtype: tuple + @return: Polar coordinates (r, t) + """ + return (self.__r, math.degrees(self.__t)) + + def set_coordinate(self, r, t): + """ + Set polar coordinate + @type r: number + @param r: The radius of coordinate + @type t: number + @param t: The angle (theta) of coordinate + """ + self.__r = r + self.__t = math.radians(t) + + def to_cartesian(self): + """ + Convert polar in cartesian coordinate + @rtype: tuple + @return: cartesian coordinates (x, y) + """ + x = self.__r * math.cos(self.__t) + y = self.__r * math.sin(self.__t) + + return (x, y) + + +class CartesianCoordinate: + """ + Class to implement a cartesian coordinate object + """ + def __init__(self, x=0, y=0): + """ + Constructor method of CartesianCoordinate class + @type x: number + @param x: The x component of coordinate + @type y: number + @param y: The y component of coordinate + """ + self.__x = x + """X component of cartesian coordinate""" + self.__y = y + """Y component of cartesian coordinate""" + + def get_coordinate(self): + """ + Get cartesian coordinate + @rtype: tuple + @return: Cartesian coordinates (x, y) + """ + return (self.__x, self.__y) + + def set_coordinate(self, x, y): + """ + Set cartesian coordinate + @type x: number + @param x: The x component of coordinate + @type y: number + @param y: The y component of coordinate + """ + self.__x = x + self.__y = y + + def to_polar(self): + """ + Convert cartesian in polar coordinate + @rtype: tuple + @return: polar coordinates (r, t) + """ + r = math.sqrt(self.__x ** 2 + self.__y ** 2) + + if self.__x > 0: + + if self.__y >= 0: + t = math.atan(self.__y / self.__x) + + else: + t = math.atan(self.__y / self.__x) + 2 * math.pi + + elif self.__x < 0: + t = math.atan(self.__y / self.__x) + math.pi + + elif self.__x == 0: + + if self.__y == 0: + t = 0 + + if self.__y > 0: + t = math.pi / 2 + + else: + t = -math.pi / 2 + + return (r, t) + + +if __name__ == "__main__": + + # Testing application + + polar = PolarCoordinate(1, math.pi) + cartesian = CartesianCoordinate(-1, 0) + + print(polar.to_cartesian()) + print(cartesian.to_polar()) diff --git a/zenmap/radialnet/core/Graph.py b/zenmap/radialnet/core/Graph.py new file mode 100644 index 0000000..1e0e8b5 --- /dev/null +++ b/zenmap/radialnet/core/Graph.py @@ -0,0 +1,247 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + + +class Node(object): + """ + Node class + """ + def __init__(self): + """ + Constructor method of Node class + @type : integer + @param : Node identifier + """ + self.__data = None + """User-controlled data pointer""" + self.__edges = [] + """List of edges to other nodes""" + + def get_data(self): + return self.__data + + def set_data(self, data): + self.__data = data + + def get_edge(self, dest): + """ + Return the edge connecting to dest, or None if none + """ + for edge in self.__edges: + if dest in edge.get_nodes(): + return edge + return None + + def get_edges(self): + """ + Return the list of edges + """ + return self.__edges + + def add_edge(self, edge): + self.__edges.append(edge) + + +class Edge: + """ + """ + def __init__(self, nodes): + """ + """ + self.__weights = [] + self.__nodes = nodes + self.__weights_mean = None + + def get_nodes(self): + """ + """ + return self.__nodes + + def get_weights(self): + """ + """ + return self.__weights + + def set_weights(self, weights): + """ + """ + self.__weights = weights + self.__weights_mean = sum(self.__weights) / len(self.__weights) + + def add_weight(self, weight): + """ + """ + self.__weights.append(weight) + self.__weights_mean = sum(self.__weights) / len(self.__weights) + + def get_weights_mean(self): + """ + """ + return self.__weights_mean + + +class Graph: + """ + Network Graph class + """ + + def __init__(self): + """ + Constructor method of Graph class + @type : list + @param : List of nodes + """ + self.__main_node = None + self.__nodes = [] + self.__max_edge_mean_value = None + self.__min_edge_mean_value = None + + def set_nodes(self, nodes): + """ + """ + self.__nodes = nodes + + def get_nodes(self): + """ + """ + return self.__nodes + + def get_number_of_nodes(self): + """ + Get the number of nodes in graph + @rtype: number + @return: The number of nodes in the graph + """ + return len(self.__nodes) + + def set_main_node(self, node): + """ + Set the main node + @type : number + @param : The node + """ + self.__main_node = node + + def get_main_node(self): + """ + Get the main node + @rtype: Node + @return: The main node + """ + return self.__main_node + + def set_connection(self, a, b, weight=None): + """ + Set node connections + @type : list + @param : List of connections + """ + + # if is a new connection make it + edge = a.get_edge(b) + if edge is None: + edge = Edge((a, b)) + a.add_edge(edge) + b.add_edge(edge) + + # then add new weight value + if weight is not None: + + edge.add_weight(weight) + + mean_weight = edge.get_weights_mean() + if (self.__min_edge_mean_value is None or + mean_weight < self.__min_edge_mean_value): + self.__min_edge_mean_value = mean_weight + if (self.__max_edge_mean_value is None or + mean_weight > self.__max_edge_mean_value): + self.__max_edge_mean_value = mean_weight + + def get_edges(self): + """ + An iterator that yields all edges + """ + for node in self.__nodes: + for edge in node.get_edges(): + if edge.get_nodes()[0] == node: + yield edge + + def get_node_connections(self, node): + """ + """ + connections = [] + + for edge in node.get_edges(): + + (a, b) = edge.get_nodes() + + if a == node: + connections.append(b) + if b == node: + connections.append(a) + + return connections + + def get_max_edge_mean_weight(self): + """ + """ + return self.__max_edge_mean_value + + def get_min_edge_mean_weight(self): + """ + """ + return self.__min_edge_mean_value diff --git a/zenmap/radialnet/core/Info.py b/zenmap/radialnet/core/Info.py new file mode 100644 index 0000000..d04b31a --- /dev/null +++ b/zenmap/radialnet/core/Info.py @@ -0,0 +1,63 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + + +INFO = {'name': 'RadialNet', + 'version': '0.44', + 'website': 'http://www.dca.ufrn.br/~joaomedeiros/radialnet/', + 'authors': ['João Paulo de Souza Medeiros'], + 'copyright': 'Copyright (C) 2007, 2008 Insecure.Com LLC'} diff --git a/zenmap/radialnet/core/Interpolation.py b/zenmap/radialnet/core/Interpolation.py new file mode 100644 index 0000000..1d89498 --- /dev/null +++ b/zenmap/radialnet/core/Interpolation.py @@ -0,0 +1,157 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + + +class Linear2DInterpolator: + """ + Implements a bidimensional linear interpolator. + """ + + def __init__(self): + """ + Constructor method of Linear2DInterpolator class + """ + self.__start_point = (0, 0) + """Initial point of interpolation""" + self.__final_point = (0, 0) + """Final point of interpolation""" + self.__interpolated_points = [] + """Interpolated points vector""" + + def set_start_point(self, a, b): + """ + Set initial coordinate + Set final coordinate + @type a: number + @param a: The first component of final point + @type b: number + @param b: The second component of final point + """ + self.__start_point = (a, b) + + def set_final_point(self, a, b): + """ + Set final coordinate + @type a: number + @param a: The first component of final point + @type b: number + @param b: The second component of final point + """ + self.__final_point = (a, b) + + def get_weighed_points(self, number_of_pass, pass_vector): + """ + Return the vector of coordinates between the initial and final + coordinates with the specified size + @type number_of_pass: number + @param number_of_pass: The number of pass of interpolation + @rtype: list + @return: A list of tuples with interpolated points + """ + (ai, bi) = self.__start_point + (af, bf) = self.__final_point + + a_conversion_factor = float(af - ai) / sum(pass_vector) + b_conversion_factor = float(bf - bi) / sum(pass_vector) + + a_pass = 0 + b_pass = 0 + + self.__interpolated_points = list(range(number_of_pass)) + + for i in range(0, number_of_pass): + + a_pass += pass_vector[i] * a_conversion_factor + b_pass += pass_vector[i] * b_conversion_factor + self.__interpolated_points[i] = (ai + a_pass, bi + b_pass) + + return self.__interpolated_points + + def get_points(self, number_of_pass): + """ + Return the vector of coordinates between the initial and final + coordinates with the specified size + @type number_of_pass: number + @param number_of_pass: The number of pass of interpolation + @rtype: list + @return: A list of tuples with interpolated points + """ + (ai, bi) = self.__start_point + (af, bf) = self.__final_point + + a_pass = float(af - ai) / number_of_pass + b_pass = float(bf - bi) / number_of_pass + + self.__interpolated_points = list(range(number_of_pass)) + + for i in range(1, number_of_pass + 1): + self.__interpolated_points[i - 1] = (ai + a_pass * i, + bi + b_pass * i) + + return self.__interpolated_points + + +if __name__ == "__main__": + + # Testing application + + i = Linear2DInterpolator() + + i.set_start_point(0, 0) + i.set_final_point(1, 1) + + print(len(i.get_points(10)), i.get_points(10)) diff --git a/zenmap/radialnet/core/XMLHandler.py b/zenmap/radialnet/core/XMLHandler.py new file mode 100644 index 0000000..36eb2e1 --- /dev/null +++ b/zenmap/radialnet/core/XMLHandler.py @@ -0,0 +1,324 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + + +# Prevent loading PyXML +import xml +xml.__path__ = [x for x in xml.__path__ if "_xmlplus" not in x] + +import xml.sax +import xml.sax.saxutils +from xml.sax.xmlreader import AttributesImpl as Attributes + + +class XMLNode: + """ + """ + def __init__(self, name): + """ + """ + self.__name = name + self.__text = "" + self.__attrs = dict() + self.__children = [] + + def set_text(self, text): + """ + """ + self.__text = text + + def get_text(self): + """ + """ + return self.__text + + def set_name(self, name): + """ + """ + self.__name = name + + def get_name(self): + """ + """ + return self.__name + + def add_attr(self, key, value): + """ + """ + self.__attrs[key] = value + + def add_child(self, child): + """ + """ + self.__children.append(child) + + def get_keys(self): + """ + """ + return self.__attrs.keys() + + def get_attr(self, attr): + """ + """ + return self.__attrs.get(attr) + + def get_attrs(self): + """ + """ + return self.__attrs + + def get_children(self): + """ + """ + return self.__children + + def query_children(self, name, attr, value, first=False, deep=False): + """ + """ + result = [] + + for child in self.__children: + + if child.get_name() == name: + + if attr in child.get_attrs(): + + c_value = child.get_attr(attr) + + if c_value == value or c_value == str(value): + result.append(child) + + if deep: + + c_result = child.query_children(name, attr, value, first, deep) + + if c_result is not None: + + if first: + return c_result + + else: + result.extend(c_result) + + if first and len(result) > 0: + return result[0] + + if first: + return None + + return result + + def search_children(self, name, first=False, deep=False): + """ + """ + result = [] + + for child in self.__children: + + if child.get_name() == name: + + result.append(child) + + if first: + return result[0] + + if deep: + + c_result = child.search_children(name, first, deep) + + if c_result is not None and c_result != []: + + if first: + return c_result + + else: + result.extend(c_result) + + if first: + return None + + return result + + +class XMLWriter(xml.sax.saxutils.XMLGenerator): + """ + """ + def __init__(self, file, root=None, encoding="utf-8"): + """ + """ + xml.sax.saxutils.XMLGenerator.__init__(self, file, encoding) + + self.__root = root + + def set_root(self, root): + """ + """ + self.__root = root + + def write(self): + """ + """ + self.startDocument() + self.write_xml_node([self.__root]) + self.endDocument() + + def write_xml_node(self, root): + """ + """ + for child in root: + + self.startElement(child.get_name(), Attributes(child.get_attrs())) + + if child.get_text() != "": + self.characters(child.get_text()) + + self.write_xml_node(child.get_children()) + + self.endElement(child.get_name()) + + +class XMLReader(xml.sax.ContentHandler): + """ + """ + def __init__(self, file=None): + """ + """ + xml.sax.ContentHandler.__init__(self) + self.__text = "" + self.__status = [] + + self.__file = file + self.__root = None + + self.__parser = xml.sax.make_parser() + self.__parser.setContentHandler(self) + + def set_file(self, file, root): + """ + """ + self.__file = file + + def get_file(self): + """ + """ + return self.__file + + def get_root(self): + """ + """ + return self.__root + + def parse(self): + """ + """ + if self.__file is not None: + self.__parser.parse(self.__file) + + def startDocument(self): + """ + """ + pass + + def startElement(self, name, attrs): + """ + """ + # create new node + node = XMLNode(name) + + # putting attributes and values in node + for attr in attrs.getNames(): + node.add_attr(attr, attrs.get(attr).strip()) + + # who is my father? + if len(self.__status) > 0: + self.__status[-1].add_child(node) + + if self.__root is None: + self.__root = node + + self.__status.append(node) + + def endElement(self, name): + """ + """ + self.__status[-1].set_text(self.__text.strip()) + + self.__text = "" + self.__status.pop() + + def endDocument(self): + """ + """ + pass + + def characters(self, text): + """ + """ + self.__text += text + + +if __name__ == "__main__": + + import sys + + reader = XMLReader(sys.argv[1]) + reader.parse() + + root = reader.get_root() + + writer = XMLWriter(open("test.xml", 'w'), root) + writer.write() diff --git a/zenmap/radialnet/core/__init__.py b/zenmap/radialnet/core/__init__.py new file mode 100644 index 0000000..c314dd7 --- /dev/null +++ b/zenmap/radialnet/core/__init__.py @@ -0,0 +1,56 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ diff --git a/zenmap/radialnet/gui/Application.py b/zenmap/radialnet/gui/Application.py new file mode 100644 index 0000000..dbc6fe2 --- /dev/null +++ b/zenmap/radialnet/gui/Application.py @@ -0,0 +1,159 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk + +from radialnet.util.integration import make_graph_from_nmap_parser +from radialnet.core.Info import INFO +from radialnet.core.XMLHandler import XMLReader +from radialnet.gui.ControlWidget import ControlWidget, ControlFisheye +from radialnet.gui.Toolbar import Toolbar +from radialnet.gui.Image import Pixmaps +import radialnet.gui.RadialNet as RadialNet +from radialnet.bestwidgets.windows import BWMainWindow, BWAlertDialog +from radialnet.bestwidgets.boxes import BWHBox, BWVBox, BWStatusbar + + +DIMENSION = (640, 480) + + +class Application(BWMainWindow): + """ + """ + def __init__(self): + """ + """ + BWMainWindow.__init__(self) + self.set_default_size(DIMENSION[0], DIMENSION[1]) + + self.set_icon(Pixmaps().get_pixbuf('logo')) + + self.__create_widgets() + + def __create_widgets(self): + """ + """ + self.__hbox = BWHBox(spacing=0) + self.__vbox = BWVBox(spacing=0) + + self.__radialnet = RadialNet.RadialNet(RadialNet.LAYOUT_WEIGHTED) + self.__control = ControlWidget(self.__radialnet) + self.__fisheye = ControlFisheye(self.__radialnet) + self.__toolbar = Toolbar(self.__radialnet, + self, + self.__control, + self.__fisheye) + self.__statusbar = BWStatusbar() + + self.__hbox.bw_pack_start_expand_fill(self.__radialnet) + self.__hbox.bw_pack_start_noexpand_nofill(self.__control) + + self.__vbox.bw_pack_start_noexpand_nofill(self.__toolbar) + self.__vbox.bw_pack_start_expand_fill(self.__hbox) + self.__vbox.bw_pack_start_noexpand_nofill(self.__fisheye) + self.__vbox.bw_pack_start_noexpand_nofill(self.__statusbar) + + self.add(self.__vbox) + self.set_title(" ".join([INFO['name'], INFO['version']])) + self.set_position(Gtk.WindowPosition.CENTER) + self.show_all() + self.connect('destroy', Gtk.main_quit) + + self.__radialnet.set_no_show_all(True) + self.__control.set_no_show_all(True) + self.__fisheye.set_no_show_all(True) + + self.__radialnet.hide() + self.__control.hide() + self.__fisheye.hide() + self.__toolbar.disable_controls() + + def parse_nmap_xml_file(self, file): + """ + """ + try: + + self.__parser = XMLReader(file) + self.__parser.parse() + + except Exception as e: + + text = 'It is not possible open file %s: %s' % (file, e) + + alert = BWAlertDialog(self, + primary_text='Error opening file.', + secondary_text=text) + + alert.show_all() + + return False + + self.__radialnet.set_empty() + self.__radialnet.set_graph(make_graph_from_nmap_parser(self.__parser)) + self.__radialnet.show() + + self.__toolbar.enable_controls() + + return True + + def start(self): + """ + """ + Gtk.main() diff --git a/zenmap/radialnet/gui/ControlWidget.py b/zenmap/radialnet/gui/ControlWidget.py new file mode 100644 index 0000000..99be773 --- /dev/null +++ b/zenmap/radialnet/gui/ControlWidget.py @@ -0,0 +1,1270 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk, GLib, Gdk + +import math + +import radialnet.util.geometry as geometry + +from radialnet.bestwidgets.boxes import * +from radialnet.core.Coordinate import PolarCoordinate +import radialnet.gui.RadialNet as RadialNet +from radialnet.bestwidgets.expanders import BWExpander + + +OPTIONS = ['address', + 'hostname', + 'icon', + 'latency', + 'ring', + 'region', + 'slow in/out'] + +REFRESH_RATE = 500 + + +class ControlWidget(BWVBox): + """ + """ + def __init__(self, radialnet): + """ + """ + BWVBox.__init__(self) + self.set_border_width(6) + + self.radialnet = radialnet + + self.__create_widgets() + + def __create_widgets(self): + """ + """ + self.__action = ControlAction(self.radialnet) + self.__interpolation = ControlInterpolation(self.radialnet) + self.__layout = ControlLayout(self.radialnet) + self.__view = ControlView(self.radialnet) + + self.bw_pack_start_noexpand_nofill(self.__action) + self.bw_pack_start_noexpand_nofill(self.__interpolation) + self.bw_pack_start_noexpand_nofill(self.__layout) + self.bw_pack_start_noexpand_nofill(self.__view) + + +class ControlAction(BWExpander): + """ + """ + def __init__(self, radialnet): + """ + """ + BWExpander.__init__(self, _('Action')) + self.set_expanded(True) + + self.radialnet = radialnet + + self.__create_widgets() + + def __create_widgets(self): + """ + """ + self.__tbox = BWTable(1, 4) + self.__tbox.bw_set_spacing(0) + self.__vbox = BWVBox() + + self.__jump_to = Gtk.RadioToolButton(group=None, + stock_id=Gtk.STOCK_JUMP_TO) + self.__jump_to.set_tooltip_text('Change focus') + self.__jump_to.connect('toggled', + self.__change_pointer, + RadialNet.POINTER_JUMP_TO) + + self.__info = Gtk.RadioToolButton(group=self.__jump_to, + stock_id=Gtk.STOCK_INFO) + self.__info.set_tooltip_text('Show information') + self.__info.connect('toggled', + self.__change_pointer, + RadialNet.POINTER_INFO) + + self.__group = Gtk.RadioToolButton(group=self.__jump_to, + stock_id=Gtk.STOCK_ADD) + self.__group.set_tooltip_text('Group children') + self.__group.connect('toggled', + self.__change_pointer, + RadialNet.POINTER_GROUP) + + self.__region = Gtk.RadioToolButton(group=self.__jump_to, + stock_id=Gtk.STOCK_SELECT_COLOR) + self.__region.set_tooltip_text('Fill region') + self.__region.connect('toggled', + self.__change_pointer, + RadialNet.POINTER_FILL) + + self.__region_color = Gtk.ComboBoxText.new() + self.__region_color.append_text(_('Red')) + self.__region_color.append_text(_('Yellow')) + self.__region_color.append_text(_('Green')) + self.__region_color.connect('changed', self.__change_region) + self.__region_color.set_active(self.radialnet.get_region_color()) + + self.__tbox.bw_attach_next(self.__jump_to) + self.__tbox.bw_attach_next(self.__info) + self.__tbox.bw_attach_next(self.__group) + self.__tbox.bw_attach_next(self.__region) + + self.__vbox.bw_pack_start_noexpand_nofill(self.__tbox) + self.__vbox.bw_pack_start_noexpand_nofill(self.__region_color) + + self.bw_add(self.__vbox) + + self.__jump_to.set_active(True) + self.__region_color.set_no_show_all(True) + self.__region_color.hide() + + def __change_pointer(self, widget, pointer): + """ + """ + if pointer != self.radialnet.get_pointer_status(): + self.radialnet.set_pointer_status(pointer) + + if pointer == RadialNet.POINTER_FILL: + self.__region_color.show() + else: + self.__region_color.hide() + + def __change_region(self, widget): + """ + """ + self.radialnet.set_region_color(self.__region_color.get_active()) + + +class ControlVariableWidget(Gtk.DrawingArea): + """ + """ + def __init__(self, name, value, update, increment=1): + """ + """ + Gtk.DrawingArea.__init__(self) + + self.__variable_name = name + self.__value = value + self.__update = update + self.__increment_pass = increment + + self.__radius = 6 + self.__increment_time = 100 + + self.__pointer_position = 0 + self.__active_increment = False + + self.__last_value = self.__value() + + self.connect('draw', self.draw) + self.connect('button_press_event', self.button_press) + self.connect('button_release_event', self.button_release) + self.connect('motion_notify_event', self.motion_notify) + + self.add_events(Gdk.EventMask.BUTTON_PRESS_MASK | + Gdk.EventMask.BUTTON_RELEASE_MASK | + Gdk.EventMask.POINTER_MOTION_HINT_MASK | + Gdk.EventMask.POINTER_MOTION_MASK) + + GLib.timeout_add(REFRESH_RATE, self.verify_value) + + def verify_value(self): + """ + """ + if self.__value() != self.__last_value: + self.__last_value = self.__value() + + self.queue_draw() + + return True + + def button_press(self, widget, event): + """ + """ + self.__active_increment = False + pointer = self.get_pointer() + + if self.__button_is_clicked(pointer) and event.button == 1: + + event.window.set_cursor(Gdk.Cursor(Gdk.CursorType.HAND2)) + self.__active_increment = True + self.__increment_value() + + def button_release(self, widget, event): + """ + """ + event.window.set_cursor(Gdk.Cursor(Gdk.CursorType.LEFT_PTR)) + + self.__active_increment = False + self.__pointer_position = 0 + + self.queue_draw() + + def motion_notify(self, widget, event): + """ + Drawing callback + @type widget: GtkWidget + @param widget: Gtk widget superclass + @type event: GtkEvent + @param event: Gtk event of widget + @rtype: boolean + @return: Indicator of the event propagation + """ + if self.__active_increment: + + xc, yc = self.__center_of_widget + x, _ = self.get_pointer() + + if x - self.__radius > 0 and x + self.__radius < 2 * xc: + self.__pointer_position = x - xc + + self.queue_draw() + + def draw(self, widget, context): + """ + Drawing callback + @type widget: GtkWidget + @param widget: Gtk widget superclass + @type context: cairo.Context + @param context: cairo context class + @rtype: boolean + @return: Indicator of the event propagation + """ + self.set_size_request(100, 30) + + self.__draw(context) + + return True + + def __draw(self, context): + """ + """ + allocation = self.get_allocation() + + self.__center_of_widget = (allocation.width // 2, + allocation.height // 2) + + xc, yc = self.__center_of_widget + + # draw line + context.set_line_width(1) + context.set_dash([1, 2]) + context.move_to(self.__radius, + yc + self.__radius) + context.line_to(2 * xc - 5, + yc + self.__radius) + context.stroke() + + # draw text + context.set_dash([1, 0]) + context.set_font_size(10) + + context.move_to(5, yc - self.__radius) + context.show_text(self.__variable_name) + + width = context.text_extents(str(self.__value()))[2] + context.move_to(2 * xc - width - 5, yc - self.__radius) + context.show_text(str(self.__value())) + + context.set_line_width(1) + context.stroke() + + # draw node + context.arc(xc + self.__pointer_position, + yc + self.__radius, + self.__radius, 0, 2 * math.pi) + if self.__active_increment: + context.set_source_rgb(0.0, 0.0, 0.0) + else: + context.set_source_rgb(1.0, 1.0, 1.0) + context.fill_preserve() + context.set_source_rgb(0.0, 0.0, 0.0) + context.stroke() + + def __button_is_clicked(self, pointer): + """ + """ + xc, yc = self.__center_of_widget + center = (xc, yc + self.__radius) + + return geometry.is_in_circle(pointer, 6, center) + + def __increment_value(self): + """ + """ + self.__update(self.__value() + self.__pointer_position / 4) + + self.queue_draw() + + if self.__active_increment: + + GLib.timeout_add(self.__increment_time, + self.__increment_value) + + def set_value_function(self, value): + """ + """ + self.__value = value + + def set_update_function(self, update): + """ + """ + self.__update = update + + +class ControlVariable(BWHBox): + """ + """ + def __init__(self, name, get_function, set_function, increment=1): + """ + """ + BWHBox.__init__(self, spacing=0) + + self.__increment_pass = increment + self.__increment_time = 200 + self.__increment = False + + self.__name = name + self.__get_function = get_function + self.__set_function = set_function + + self.__create_widgets() + + def __create_widgets(self): + """ + """ + self.__control = ControlVariableWidget(self.__name, + self.__get_function, + self.__set_function, + self.__increment_pass) + + self.__left_button = Gtk.Button() + self.__left_button.set_size_request(20, 20) + self.__left_arrow = Gtk.Image.new_from_icon_name("pan-start-symbolic", + Gtk.IconSize.BUTTON); + self.__left_button.add(self.__left_arrow) + self.__left_button.connect('pressed', + self.__pressed, + -self.__increment_pass) + self.__left_button.connect('released', self.__released) + + self.__right_button = Gtk.Button() + self.__right_button.set_size_request(20, 20) + self.__right_arrow = Gtk.Image.new_from_icon_name("pan-end-symbolic", + Gtk.IconSize.BUTTON); + self.__right_button.add(self.__right_arrow) + self.__right_button.connect('pressed', + self.__pressed, + self.__increment_pass) + self.__right_button.connect('released', self.__released) + + self.bw_pack_start_noexpand_nofill(self.__left_button) + self.bw_pack_start_expand_fill(self.__control) + self.bw_pack_start_noexpand_nofill(self.__right_button) + + def __pressed(self, widget, increment): + """ + """ + self.__increment = True + self.__increment_function(increment) + + def __increment_function(self, increment): + """ + """ + if self.__increment: + + self.__set_function(self.__get_function() + increment) + self.__control.verify_value() + + GLib.timeout_add(self.__increment_time, + self.__increment_function, + increment) + + def __released(self, widget): + """ + """ + self.__increment = False + + +class ControlFisheye(BWVBox): + """ + """ + def __init__(self, radialnet): + """ + """ + BWVBox.__init__(self) + self.set_border_width(6) + + self.radialnet = radialnet + self.__ring_max_value = self.radialnet.get_number_of_rings() + + self.__create_widgets() + + def __create_widgets(self): + """ + """ + self.__params = BWHBox() + + self.__fisheye_label = Gtk.Label.new(_('<b>Fisheye</b> on ring')) + self.__fisheye_label.set_use_markup(True) + + self.__ring = Gtk.Adjustment.new(0, 0, self.__ring_max_value, 0.01, 0.01, 0) + + self.__ring_spin = Gtk.SpinButton(adjustment=self.__ring) + self.__ring_spin.set_digits(2) + + self.__ring_scale = Gtk.Scale(orientation=Gtk.Orientation.HORIZONTAL, adjustment=self.__ring) + self.__ring_scale.set_size_request(100, -1) + self.__ring_scale.set_digits(2) + self.__ring_scale.set_value_pos(Gtk.PositionType.LEFT) + self.__ring_scale.set_draw_value(False) + + self.__interest_label = Gtk.Label.new(_('with interest factor')) + self.__interest = Gtk.Adjustment.new(0, 0, 10, 0.01, 0, 0) + self.__interest_spin = Gtk.SpinButton(adjustment=self.__interest) + self.__interest_spin.set_digits(2) + + self.__spread_label = Gtk.Label.new(_('and spread factor')) + self.__spread = Gtk.Adjustment.new(0, -1.0, 1.0, 0.01, 0.01, 0) + self.__spread_spin = Gtk.SpinButton(adjustment=self.__spread) + self.__spread_spin.set_digits(2) + + self.__params.bw_pack_start_noexpand_nofill(self.__fisheye_label) + self.__params.bw_pack_start_noexpand_nofill(self.__ring_spin) + self.__params.bw_pack_start_expand_fill(self.__ring_scale) + self.__params.bw_pack_start_noexpand_nofill(self.__interest_label) + self.__params.bw_pack_start_noexpand_nofill(self.__interest_spin) + self.__params.bw_pack_start_noexpand_nofill(self.__spread_label) + self.__params.bw_pack_start_noexpand_nofill(self.__spread_spin) + + self.bw_pack_start_noexpand_nofill(self.__params) + + self.__ring.connect('value_changed', self.__change_ring) + self.__interest.connect('value_changed', self.__change_interest) + self.__spread.connect('value_changed', self.__change_spread) + + GLib.timeout_add(REFRESH_RATE, self.__update_fisheye) + + def __update_fisheye(self): + """ + """ + # adjust ring scale to radialnet number of nodes + ring_max_value = self.radialnet.get_number_of_rings() - 1 + + if ring_max_value != self.__ring_max_value: + + value = self.__ring.get_value() + + if value == 0 and ring_max_value != 0: + value = 1 + + elif value > ring_max_value: + value = ring_max_value + + self.__ring.configure(value, 1, ring_max_value, 0.01, 0.01, 0) + self.__ring_max_value = ring_max_value + + self.__ring_scale.queue_draw() + + # check ring value + ring_value = self.radialnet.get_fisheye_ring() + + if self.__ring.get_value() != ring_value: + self.__ring.set_value(ring_value) + + # check interest value + interest_value = self.radialnet.get_fisheye_interest() + + if self.__interest.get_value() != interest_value: + self.__interest.set_value(interest_value) + + # check spread value + spread_value = self.radialnet.get_fisheye_spread() + + if self.__spread.get_value() != spread_value: + self.__spread.set_value(spread_value) + + return True + + def active_fisheye(self): + """ + """ + self.radialnet.set_fisheye(True) + self.__change_ring() + self.__change_interest() + + def deactive_fisheye(self): + """ + """ + self.radialnet.set_fisheye(False) + + def __change_ring(self, widget=None): + """ + """ + if not self.radialnet.is_in_animation(): + self.radialnet.set_fisheye_ring(self.__ring.get_value()) + else: + self.__ring.set_value(self.radialnet.get_fisheye_ring()) + + def __change_interest(self, widget=None): + """ + """ + if not self.radialnet.is_in_animation(): + self.radialnet.set_fisheye_interest(self.__interest.get_value()) + else: + self.__interest.set_value(self.radialnet.get_fisheye_interest()) + + def __change_spread(self, widget=None): + """ + """ + if not self.radialnet.is_in_animation(): + self.radialnet.set_fisheye_spread(self.__spread.get_value()) + else: + self.__spread.set_value(self.radialnet.get_fisheye_spread()) + + +class ControlInterpolation(BWExpander): + """ + """ + def __init__(self, radialnet): + """ + """ + BWExpander.__init__(self, _('Interpolation')) + + self.radialnet = radialnet + + self.__create_widgets() + + def __create_widgets(self): + """ + """ + self.__vbox = BWVBox() + + self.__cartesian_radio = Gtk.RadioButton(group=None, + label=_('Cartesian')) + self.__polar_radio = Gtk.RadioButton(group=self.__cartesian_radio, + label=_('Polar')) + self.__cartesian_radio.connect('toggled', + self.__change_system, + RadialNet.INTERPOLATION_CARTESIAN) + self.__polar_radio.connect('toggled', + self.__change_system, + RadialNet.INTERPOLATION_POLAR) + + self.__system_box = BWHBox() + self.__system_box.bw_pack_start_noexpand_nofill(self.__polar_radio) + self.__system_box.bw_pack_start_noexpand_nofill(self.__cartesian_radio) + + self.__frames_box = BWHBox() + self.__frames_label = Gtk.Label.new(_('Frames')) + self.__frames_label.set_alignment(0.0, 0.5) + self.__frames = Gtk.Adjustment.new( + self.radialnet.get_number_of_frames(), 1, 1000, 1, 0, 0) + self.__frames.connect('value_changed', self.__change_frames) + self.__frames_spin = Gtk.SpinButton(adjustment=self.__frames) + self.__frames_box.bw_pack_start_expand_fill(self.__frames_label) + self.__frames_box.bw_pack_start_noexpand_nofill(self.__frames_spin) + + self.__vbox.bw_pack_start_noexpand_nofill(self.__frames_box) + self.__vbox.bw_pack_start_noexpand_nofill(self.__system_box) + + self.bw_add(self.__vbox) + + GLib.timeout_add(REFRESH_RATE, self.__update_animation) + + def __update_animation(self): + """ + """ + active = self.radialnet.get_interpolation() + + if active == RadialNet.INTERPOLATION_CARTESIAN: + self.__cartesian_radio.set_active(True) + + else: + self.__polar_radio.set_active(True) + + return True + + def __change_system(self, widget, value): + """ + """ + if not self.radialnet.set_interpolation(value): + + active = self.radialnet.get_interpolation() + + if active == RadialNet.INTERPOLATION_CARTESIAN: + self.__cartesian_radio.set_active(True) + + else: + self.__polar_radio.set_active(True) + + def __change_frames(self, widget): + """ + """ + if not self.radialnet.set_number_of_frames(self.__frames.get_value()): + self.__frames.set_value(self.radialnet.get_number_of_frames()) + + +class ControlLayout(BWExpander): + """ + """ + def __init__(self, radialnet): + """ + """ + BWExpander.__init__(self, _('Layout')) + + self.radialnet = radialnet + + self.__create_widgets() + + def __create_widgets(self): + """ + """ + self.__hbox = BWHBox() + + self.__layout = Gtk.ComboBoxText() + self.__layout.append_text(_('Symmetric')) + self.__layout.append_text(_('Weighted')) + self.__layout.set_active(self.radialnet.get_layout()) + self.__layout.connect('changed', self.__change_layout) + self.__force = Gtk.ToolButton(stock_id=Gtk.STOCK_REFRESH) + self.__force.connect('clicked', self.__force_update) + + self.__hbox.bw_pack_start_expand_fill(self.__layout) + self.__hbox.bw_pack_start_noexpand_nofill(self.__force) + + self.bw_add(self.__hbox) + + self.__check_layout() + + def __check_layout(self): + """ + """ + if self.__layout.get_active() == RadialNet.LAYOUT_WEIGHTED: + self.__force.set_sensitive(True) + + else: + self.__force.set_sensitive(False) + + return True + + def __force_update(self, widget): + """ + """ + self.__fisheye_ring = self.radialnet.get_fisheye_ring() + self.radialnet.update_layout() + + def __change_layout(self, widget): + """ + """ + if not self.radialnet.set_layout(self.__layout.get_active()): + self.__layout.set_active(self.radialnet.get_layout()) + + else: + self.__check_layout() + + +class ControlRingGap(BWVBox): + """ + """ + def __init__(self, radialnet): + """ + """ + BWVBox.__init__(self) + + self.radialnet = radialnet + + self.__create_widgets() + + def __create_widgets(self): + """ + """ + self.__radius = ControlVariable(_('Ring gap'), + self.radialnet.get_ring_gap, + self.radialnet.set_ring_gap) + + self.__label = Gtk.Label.new(_('Lower ring gap')) + self.__label.set_alignment(0.0, 0.5) + self.__adjustment = Gtk.Adjustment.new( + self.radialnet.get_min_ring_gap(), 0, 50, 1, 0, 0) + self.__spin = Gtk.SpinButton(adjustment=self.__adjustment) + self.__spin.connect('value_changed', self.__change_lower) + + self.__lower_hbox = BWHBox() + self.__lower_hbox.bw_pack_start_expand_fill(self.__label) + self.__lower_hbox.bw_pack_start_noexpand_nofill(self.__spin) + + self.bw_pack_start_noexpand_nofill(self.__radius) + self.bw_pack_start_noexpand_nofill(self.__lower_hbox) + + def __change_lower(self, widget): + """ + """ + if not self.radialnet.set_min_ring_gap(self.__adjustment.get_value()): + self.__adjustment.set_value(self.radialnet.get_min_ring_gap()) + + +class ControlOptions(BWScrolledWindow): + """ + """ + def __init__(self, radialnet): + """ + """ + BWScrolledWindow.__init__(self) + + self.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.ALWAYS) + self.set_shadow_type(Gtk.ShadowType.NONE) + + self.radialnet = radialnet + + self.enable_labels = True + + self.__create_widgets() + + def __create_widgets(self): + """ + """ + self.__liststore = Gtk.ListStore.new([bool, str]) + + self.__liststore.append([None, OPTIONS[0]]) + self.__liststore.append([None, OPTIONS[1]]) + self.__liststore.append([None, OPTIONS[2]]) + self.__liststore.append([None, OPTIONS[3]]) + self.__liststore.append([None, OPTIONS[4]]) + self.__liststore.append([None, OPTIONS[5]]) + self.__liststore.append([None, OPTIONS[6]]) + + self.__cell_toggle = Gtk.CellRendererToggle() + self.__cell_toggle.set_property('activatable', True) + self.__cell_toggle.connect('toggled', + self.__change_option, + self.__liststore) + + self.__column_toggle = Gtk.TreeViewColumn(cell_renderer=self.__cell_toggle) + self.__column_toggle.add_attribute(self.__cell_toggle, 'active', 0) + self.__column_toggle.set_cell_data_func(self.__cell_toggle, self.__cell_toggle_data_method) + + self.__cell_text = Gtk.CellRendererText() + + self.__column_text = Gtk.TreeViewColumn(title=None, + cell_renderer=self.__cell_text, + text=1) + self.__column_text.set_cell_data_func(self.__cell_text, self.__cell_text_data_method) + + self.__treeview = Gtk.TreeView.new_with_model(self.__liststore) + self.__treeview.set_enable_search(True) + self.__treeview.set_search_column(1) + self.__treeview.set_headers_visible(False) + self.__treeview.append_column(self.__column_toggle) + self.__treeview.append_column(self.__column_text) + + self.add_with_viewport(self.__treeview) + + GLib.timeout_add(REFRESH_RATE, self.__update_options) + + def __cell_toggle_data_method(self, column, cell, model, it, data): + if not self.enable_labels and model.get_value(it, 1) == 'hostname': + cell.set_property('activatable', False) + else: + cell.set_property('activatable', True) + + def __cell_text_data_method(self, column, cell, model, it, data): + if not self.enable_labels and model.get_value(it, 1) == 'hostname': + cell.set_property('strikethrough', True) + else: + cell.set_property('strikethrough', False) + + def __update_options(self): + """ + """ + model = self.__liststore + + model[OPTIONS.index('address')][0] = self.radialnet.get_show_address() + model[OPTIONS.index('hostname')][0] = self.enable_labels and \ + self.radialnet.get_show_hostname() + model[OPTIONS.index('icon')][0] = self.radialnet.get_show_icon() + model[OPTIONS.index('latency')][0] = self.radialnet.get_show_latency() + model[OPTIONS.index('ring')][0] = self.radialnet.get_show_ring() + model[OPTIONS.index('region')][0] = self.radialnet.get_show_region() + model[OPTIONS.index('slow in/out')][0] = \ + self.radialnet.get_slow_inout() + + return True + + def __change_option(self, cell, option, model): + """ + """ + option = int(option) + model[option][0] = not model[option][0] + + if OPTIONS[option] == 'address': + self.radialnet.set_show_address(model[option][0]) + if model[option][0]: + model[OPTIONS.index('hostname')][0] = self.radialnet.get_show_hostname() + else: + model[OPTIONS.index('hostname')][0] = False + self.enable_labels = model[option][0] + + elif OPTIONS[option] == 'hostname': + self.radialnet.set_show_hostname(model[option][0]) + + elif OPTIONS[option] == 'icon': + self.radialnet.set_show_icon(model[option][0]) + + elif OPTIONS[option] == 'latency': + self.radialnet.set_show_latency(model[option][0]) + + elif OPTIONS[option] == 'ring': + self.radialnet.set_show_ring(model[option][0]) + + elif OPTIONS[option] == 'region': + self.radialnet.set_show_region(model[option][0]) + + elif OPTIONS[option] == 'slow in/out': + self.radialnet.set_slow_inout(model[option][0]) + + +class ControlView(BWExpander): + """ + """ + def __init__(self, radialnet): + """ + """ + BWExpander.__init__(self, _('View')) + self.set_expanded(True) + + self.radialnet = radialnet + + self.__create_widgets() + + def __create_widgets(self): + """ + """ + self.__vbox = BWVBox(spacing=0) + + self.__zoom = ControlVariable(_('Zoom'), + self.radialnet.get_zoom, + self.radialnet.set_zoom) + + self.__ring_gap = ControlRingGap(self.radialnet) + self.__navigation = ControlNavigation(self.radialnet) + + self.__options = ControlOptions(self.radialnet) + self.__options.set_border_width(0) + + self.__vbox.bw_pack_start_expand_nofill(self.__options) + self.__vbox.bw_pack_start_noexpand_nofill(self.__navigation) + self.__vbox.bw_pack_start_noexpand_nofill(self.__zoom) + self.__vbox.bw_pack_start_noexpand_nofill(self.__ring_gap) + + self.bw_add(self.__vbox) + + +class ControlNavigation(Gtk.DrawingArea): + """ + """ + def __init__(self, radialnet): + """ + """ + Gtk.DrawingArea.__init__(self) + + self.radialnet = radialnet + + self.__rotate_node = PolarCoordinate() + self.__rotate_node.set_coordinate(40, 90) + self.__center_of_widget = (50, 50) + self.__moving = None + self.__centering = False + self.__rotating = False + self.__move_pass = 100 + + self.__move_position = (0, 0) + self.__move_addition = [(-1, 0), + (-1, -1), + (0, -1), + (1, -1), + (1, 0), + (1, 1), + (0, 1), + (-1, 1)] + + self.__move_factor = 1 + self.__move_factor_limit = 20 + + self.__rotate_radius = 6 + self.__move_radius = 6 + + self.__rotate_clicked = False + self.__move_clicked = None + + self.connect('draw', self.draw) + self.connect('button_press_event', self.button_press) + self.connect('button_release_event', self.button_release) + self.connect('motion_notify_event', self.motion_notify) + self.connect('enter_notify_event', self.enter_notify) + self.connect('leave_notify_event', self.leave_notify) + self.connect('key_press_event', self.key_press) + self.connect('key_release_event', self.key_release) + + self.add_events(Gdk.EventMask.BUTTON_PRESS_MASK | + Gdk.EventMask.BUTTON_RELEASE_MASK | + Gdk.EventMask.ENTER_NOTIFY_MASK | + Gdk.EventMask.LEAVE_NOTIFY_MASK | + Gdk.EventMask.KEY_PRESS_MASK | + Gdk.EventMask.KEY_RELEASE_MASK | + Gdk.EventMask.POINTER_MOTION_HINT_MASK | + Gdk.EventMask.POINTER_MOTION_MASK) + + self.__rotate_node.set_coordinate(40, self.radialnet.get_rotation()) + + def key_press(self, widget, event): + """ + """ + # key = Gdk.keyval_name(event.keyval) + + self.queue_draw() + + return True + + def key_release(self, widget, event): + """ + """ + # key = Gdk.keyval_name(event.keyval) + + self.queue_draw() + + return True + + def enter_notify(self, widget, event): + """ + """ + return False + + def leave_notify(self, widget, event): + """ + """ + self.queue_draw() + + return False + + def button_press(self, widget, event): + """ + Drawing callback + @type widget: GtkWidget + @param widget: Gtk widget superclass + @type event: GtkEvent + @param event: Gtk event of widget + @rtype: boolean + @return: Indicator of the event propagation + """ + pointer = self.get_pointer() + + direction = False + + if self.__rotate_is_clicked(pointer): + + event.window.set_cursor(Gdk.Cursor(Gdk.CursorType.HAND2)) + self.__rotating = True + + direction = self.__move_is_clicked(pointer) + + if direction is not None and self.__moving is None: + + event.window.set_cursor(Gdk.Cursor(Gdk.CursorType.HAND2)) + self.__moving = direction + self.__move_in_direction(direction) + + if self.__center_is_clicked(pointer): + + event.window.set_cursor(Gdk.Cursor(Gdk.CursorType.HAND2)) + self.__centering = True + self.__move_position = (0, 0) + self.radialnet.set_translation(self.__move_position) + + self.queue_draw() + + return False + + def button_release(self, widget, event): + """ + Drawing callback + @type widget: GtkWidget + @param widget: Gtk widget superclass + @type event: GtkEvent + @param event: Gtk event of widget + @rtype: boolean + @return: Indicator of the event propagation + """ + self.__moving = None # stop moving + self.__centering = False + self.__rotating = False # stop rotate + self.__move_factor = 1 + + event.window.set_cursor(Gdk.Cursor(Gdk.CursorType.LEFT_PTR)) + + self.queue_draw() + + return False + + def motion_notify(self, widget, event): + """ + Drawing callback + @type widget: GtkWidget + @param widget: Gtk widget superclass + @type event: GtkEvent + @param event: Gtk event of widget + @rtype: boolean + @return: Indicator of the event propagation + """ + xc, yc = self.__center_of_widget + x, y = self.get_pointer() + + status = not self.radialnet.is_in_animation() + status = status and not self.radialnet.is_empty() + + if self.__rotating and status: + + r, t = self.__rotate_node.get_coordinate() + t = math.degrees(math.atan2(yc - y, x - xc)) + + if t < 0: + t = 360 + t + + self.radialnet.set_rotation(t) + self.__rotate_node.set_coordinate(r, t) + + self.queue_draw() + + return False + + def draw(self, widget, context): + """ + Drawing callback + @type widget: GtkWidget + @param widget: Gtk widget superclass + @type context: cairo.Context + @param context: cairo context class + @rtype: boolean + @return: Indicator of the event propagation + """ + self.set_size_request(120, 130) + + self.__draw(context) + + return False + + def __draw_rotate_control(self, context): + """ + """ + xc, yc = self.__center_of_widget + r, t = self.__rotate_node.get_coordinate() + x, y = self.__rotate_node.to_cartesian() + + # draw text + context.set_font_size(10) + context.move_to(xc - 49, yc - 48) + context.show_text(_("Navigation")) + + width = context.text_extents(str(int(t)))[2] + context.move_to(xc + 49 - width - 2, yc - 48) + context.show_text(str(round(t, 1))) + context.set_line_width(1) + context.stroke() + + # draw arc + context.set_dash([1, 2]) + context.arc(xc, yc, 40, 0, 2 * math.pi) + context.set_source_rgb(0.0, 0.0, 0.0) + context.set_line_width(1) + context.stroke() + + # draw node + context.set_dash([1, 0]) + context.arc(xc + x, yc - y, self.__rotate_radius, 0, 2 * math.pi) + + if self.__rotating: + context.set_source_rgb(0.0, 0.0, 0.0) + else: + context.set_source_rgb(1.0, 1.0, 1.0) + + context.fill_preserve() + context.set_source_rgb(0.0, 0.0, 0.0) + context.set_line_width(1) + context.stroke() + + return False + + def __draw_move_control(self, context): + """ + """ + xc, yc = self.__center_of_widget + pc = PolarCoordinate() + + context.set_dash([1, 1]) + context.arc(xc, yc, 23, 0, 2 * math.pi) + context.set_source_rgb(0.0, 0.0, 0.0) + context.set_line_width(1) + context.stroke() + + for i in range(8): + + pc.set_coordinate(23, 45 * i) + x, y = pc.to_cartesian() + + context.set_dash([1, 1]) + context.move_to(xc, yc) + context.line_to(xc + x, yc - y) + context.stroke() + + context.set_dash([1, 0]) + context.arc( + xc + x, yc - y, self.__move_radius, 0, 2 * math.pi) + + if i == self.__moving: + context.set_source_rgb(0.0, 0.0, 0.0) + else: + context.set_source_rgb(1.0, 1.0, 1.0) + context.fill_preserve() + context.set_source_rgb(0.0, 0.0, 0.0) + context.set_line_width(1) + context.stroke() + + context.arc(xc, yc, 6, 0, 2 * math.pi) + + if self.__centering: + context.set_source_rgb(0.0, 0.0, 0.0) + else: + context.set_source_rgb(1.0, 1.0, 1.0) + context.fill_preserve() + context.set_source_rgb(0.0, 0.0, 0.0) + context.set_line_width(1) + context.stroke() + + return False + + def __draw(self, context): + """ + Drawing method + """ + # Getting allocation reference + allocation = self.get_allocation() + + self.__center_of_widget = (allocation.width // 2, + allocation.height // 2) + + self.__draw_rotate_control(context) + self.__draw_move_control(context) + + return False + + def __move_in_direction(self, direction): + """ + """ + if self.__moving is not None: + + bx, by = self.__move_position + ax, ay = self.__move_addition[direction] + + self.__move_position = (bx + self.__move_factor * ax, + by + self.__move_factor * ay) + self.radialnet.set_translation(self.__move_position) + + if self.__move_factor < self.__move_factor_limit: + self.__move_factor += 1 + + GLib.timeout_add(self.__move_pass, + self.__move_in_direction, + direction) + + return False + + def __rotate_is_clicked(self, pointer): + """ + """ + xn, yn = self.__rotate_node.to_cartesian() + xc, yc = self.__center_of_widget + + center = (xc + xn, yc - yn) + return geometry.is_in_circle(pointer, self.__rotate_radius, center) + + def __center_is_clicked(self, pointer): + """ + """ + return geometry.is_in_circle(pointer, self.__move_radius, + self.__center_of_widget) + + def __move_is_clicked(self, pointer): + """ + """ + xc, yc = self.__center_of_widget + pc = PolarCoordinate() + + for i in range(8): + + pc.set_coordinate(23, 45 * i) + x, y = pc.to_cartesian() + + center = (xc + x, yc - y) + if geometry.is_in_circle(pointer, self.__move_radius, center): + return i + + return None diff --git a/zenmap/radialnet/gui/Dialogs.py b/zenmap/radialnet/gui/Dialogs.py new file mode 100644 index 0000000..01d97f2 --- /dev/null +++ b/zenmap/radialnet/gui/Dialogs.py @@ -0,0 +1,89 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk + +from radialnet.core.Info import INFO +from radialnet.gui.Image import Pixmaps + + +class AboutDialog(Gtk.AboutDialog): + """ + """ + def __init__(self): + """ + """ + Gtk.AboutDialog.__init__(self) + + self.set_name(INFO['name']) + self.set_version(INFO['version']) + self.set_website(INFO['website']) + self.set_authors(INFO['authors']) + self.set_license(INFO['license']) + self.set_copyright(INFO['copyright']) + + self.set_logo(Pixmaps().get_pixbuf('logo')) + + self.connect('response', self.__destroy) + + def __destroy(self, dialog, id): + """ + """ + self.destroy() diff --git a/zenmap/radialnet/gui/HostsViewer.py b/zenmap/radialnet/gui/HostsViewer.py new file mode 100644 index 0000000..feb0ae8 --- /dev/null +++ b/zenmap/radialnet/gui/HostsViewer.py @@ -0,0 +1,231 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk + +import re + +from radialnet.bestwidgets.windows import BWMainWindow + +from radialnet.gui.NodeNotebook import NodeNotebook +from radialnet.util.misc import ipv4_compare + + +HOSTS_COLORS = ['#d5ffd5', '#ffffd5', '#ffd5d5'] + +HOSTS_HEADER = ['ID', '#', 'Hosts'] + +DIMENSION = (700, 400) + +IP_RE = re.compile(r'^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$') + + +class HostsViewer(BWMainWindow): + """ + """ + def __init__(self, nodes): + """ + """ + BWMainWindow.__init__(self) + self.set_title(_('Hosts Viewer')) + self.set_default_size(DIMENSION[0], DIMENSION[1]) + + self.__nodes = nodes + self.__default_view = Gtk.Label.new(_("No node selected")) + self.__view = self.__default_view + + self.__create_widgets() + + def __create_widgets(self): + """ + """ + self.__panel = Gtk.Paned.new(Gtk.Orientation.HORIZONTAL) + self.__panel.set_border_width(6) + + self.__list = HostsList(self, self.__nodes) + + self.__panel.add1(self.__list) + self.__panel.add2(self.__view) + self.__panel.set_position(int(DIMENSION[0] / 5)) + + self.add(self.__panel) + + def change_notebook(self, node): + """ + """ + if self.__view is not None: + self.__view.destroy() + + if node is not None: + self.__view = NodeNotebook(node) + else: + self.__view = self.__default_view + self.__view.show_all() + + self.__panel.add2(self.__view) + + +class HostsList(Gtk.ScrolledWindow): + """ + """ + def __init__(self, parent, nodes): + """ + """ + super(HostsList, self).__init__() + self.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) + self.set_shadow_type(Gtk.ShadowType.NONE) + + self.__parent = parent + self.__nodes = nodes + + self.__create_widgets() + + def __create_widgets(self): + """ + """ + self.__cell = Gtk.CellRendererText() + + self.__hosts_store = Gtk.ListStore.new([int, int, str, str, bool]) + + self.__hosts_treeview = Gtk.TreeView.new_with_model(self.__hosts_store) + self.__hosts_treeview.connect('cursor-changed', self.__cursor_callback) + + for i in range(len(self.__nodes)): + + node = self.__nodes[i] + + ports = node.get_info('number_of_open_ports') + color = HOSTS_COLORS[node.get_info('vulnerability_score')] + + host = node.get_info('hostname') or node.get_info('ip') or "" + + self.__hosts_store.append([i, + ports, + host, + color, + True]) + + self.__hosts_column = list() + + for i in range(0, len(HOSTS_HEADER)): + + column = Gtk.TreeViewColumn(title=HOSTS_HEADER[i], + cell_renderer=self.__cell, + text=i) + + self.__hosts_column.append(column) + + self.__hosts_column[i].set_reorderable(True) + self.__hosts_column[i].set_resizable(True) + self.__hosts_column[i].set_attributes(self.__cell, + text=i, + background=3, + editable=4) + + self.__hosts_treeview.append_column(self.__hosts_column[2]) + + self.__hosts_store.set_sort_func(2, self.__host_sort) + + self.__hosts_column[2].set_sort_column_id(2) + + self.add_with_viewport(self.__hosts_treeview) + + if len(self.__hosts_treeview.get_model()) > 0: + self.__hosts_treeview.set_cursor((0,)) + self.__cursor_callback(self.__hosts_treeview) + + def __cursor_callback(self, widget): + """ + """ + path = widget.get_cursor()[0] + if path is None: + return + + iter = self.__hosts_store.get_iter(path) + + node = self.__nodes[self.__hosts_store.get_value(iter, 0)] + + self.__parent.change_notebook(node) + + def __host_sort(self, treemodel, iter1, iter2, *_): + """ + """ + value1 = treemodel.get_value(iter1, 2) + value2 = treemodel.get_value(iter2, 2) + + value1_is_ip = IP_RE.match(value1) + value2_is_ip = IP_RE.match(value2) + + if value1_is_ip and value2_is_ip: + return ipv4_compare(value1, value2) + + if value1_is_ip: + return -1 + + if value2_is_ip: + return 1 + + if value1 < value2: + return -1 + + if value1 > value2: + return 1 + + return 0 diff --git a/zenmap/radialnet/gui/Image.py b/zenmap/radialnet/gui/Image.py new file mode 100644 index 0000000..72020ca --- /dev/null +++ b/zenmap/radialnet/gui/Image.py @@ -0,0 +1,164 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import GdkPixbuf + +import os +import array + +from zenmapCore.Paths import Path + + +FORMAT_RGBA = 4 +FORMAT_RGB = 3 + + +def get_pixels_for_cairo_image_surface(pixbuf): + """ + This method return the image stride and a python array.ArrayType + containing the icon pixels of a gtk.gdk.Pixbuf that can be used by + cairo.ImageSurface.create_for_data() method. + """ + data = array.array('B') + image_format = pixbuf.get_rowstride() // pixbuf.get_width() + + i = 0 + j = 0 + while i < len(pixbuf.get_pixels()): + + b, g, r = pixbuf.get_pixels()[i:i + FORMAT_RGB] + + if image_format == FORMAT_RGBA: + a = pixbuf.get_pixels()[i + FORMAT_RGBA - 1] + elif image_format == FORMAT_RGB: + a = 255 + else: + raise TypeError('unknown image format') + + data[j:j + FORMAT_RGBA] = array.array('B', [r, g, b, a]) + + i += image_format + j += FORMAT_RGBA + + return (FORMAT_RGBA * pixbuf.get_width(), data) + + +class Image: + """ + """ + def __init__(self, path=None): + """ + """ + self.__path = path + self.__cache = dict() + + def set_path(self, path): + """ + """ + self.__path = path + + def get_pixbuf(self, icon, image_type='png'): + """ + """ + if self.__path is None: + return False + + if icon + image_type not in self.__cache.keys(): + + file = self.get_icon(icon, image_type) + self.__cache[icon + image_type] = \ + GdkPixbuf.Pixbuf.new_from_file(file) + + return self.__cache[icon + image_type] + + def get_icon(self, icon, image_type='png'): + """ + """ + if self.__path is None: + return False + + return os.path.join(self.__path, icon + "." + image_type) + + +class Pixmaps(Image): + """ + """ + def __init__(self): + """ + """ + Image.__init__(self, os.path.join(Path.pixmaps_dir, "radialnet")) + + +class Icons(Image): + """ + """ + def __init__(self): + """ + """ + Image.__init__(self, os.path.join(Path.pixmaps_dir, "radialnet")) + + +class Application(Image): + """ + """ + def __init__(self): + """ + """ + Image.__init__(self, os.path.join(Path.pixmaps_dir, "radialnet")) diff --git a/zenmap/radialnet/gui/LegendWindow.py b/zenmap/radialnet/gui/LegendWindow.py new file mode 100644 index 0000000..3401e43 --- /dev/null +++ b/zenmap/radialnet/gui/LegendWindow.py @@ -0,0 +1,242 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk, Gdk, Pango + +import math +import cairo + +import zenmapCore.I18N # lgtm[py/unused-import] + +from radialnet.gui.Image import Pixmaps +DIMENSION_NORMAL = (350, 450) + + +def draw_pixmap(context, x, y, name, label): + # This is pretty hideous workaround + Gdk.cairo_set_source_pixbuf(context, Pixmaps().get_pixbuf(name), x, y) + #context.set_source_pixbuf() + context.paint() + context.move_to(x + 50, y + 10) + context.set_source_rgb(0, 0, 0) + context.show_text(label) + + +def reset_font(context): + context.select_font_face( + "Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_SLANT_NORMAL) + context.set_font_size(11) + + +def draw_heading(context, x, y, label): + context.select_font_face( + "Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) + context.set_font_size(13) + context.move_to(x - 15, y) + context.set_source_rgb(0, 0, 0) + context.show_text(label) + reset_font(context) + + +def draw_circle(context, x, y, size, color, label): + context.set_source_rgb(0, 0, 0) + context.move_to(x, y) + context.arc(x, y, size, 0, 2 * math.pi) + context.stroke_preserve() + context.set_source_rgb(*color) + context.fill() + context.set_source_rgb(0, 0, 0) + context.move_to(x + 50, y + 5) + context.show_text(label) + + +def draw_square(context, x, y, size, color): + context.set_source_rgb(0, 0, 0) + context.rectangle(x, y - size / 2, size, size) + context.stroke_preserve() + context.set_source_rgb(*color) + context.fill() + + +def draw_line(context, x, y, dash, color, label): + context.set_source_rgb(*color) + context.move_to(x - 20, y) + context.set_dash(dash) + context.line_to(x + 25, y) + context.stroke() + context.set_dash([]) + context.set_source_rgb(0, 0, 0) + context.move_to(x + 50, y + 5) + context.show_text(label) + + +class LegendWindow(Gtk.Window): + """ + """ + def __init__(self): + """ + """ + Gtk.Window.__init__(self, type=Gtk.WindowType.TOPLEVEL) + self.set_default_size(DIMENSION_NORMAL[0], DIMENSION_NORMAL[1]) + self.__title_font = Pango.FontDescription("Monospace Bold") + self.set_title(_("Topology Legend")) + + self.vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0) + self.add(self.vbox) + + self.drawing_area = Gtk.DrawingArea() + self.vbox.pack_start(self.drawing_area, True, True, 0) + self.drawing_area.connect("draw", self.draw_event_handler) + self.more_uri = Gtk.LinkButton.new_with_label( + "https://nmap.org/book/zenmap-topology.html#zenmap-topology-legend", + _("View full legend online")) + self.vbox.pack_start(self.more_uri, False, False, 0) + + def draw_event_handler(self, widget, graphic_context): + """ + """ + x, y = 45, 20 + draw_heading(graphic_context, x, y, _("Hosts")) + + # white circle + y += 20 + draw_circle(graphic_context, x, y, 3, (1, 1, 1), + _("host was not port scanned")) + # green circle + y += 20 + draw_circle(graphic_context, x, y, 4, (0, 1, 0), + _("host with fewer than 3 open ports")) + # yellow circle + y += 20 + draw_circle(graphic_context, x, y, 5, (1, 1, 0), + _("host with 3 to 6 open ports")) + # red circle + y += 20 + draw_circle(graphic_context, x, y, 6, (1, 0, 0), + _("host with more than 6 open ports")) + + # green square + y += 20 + rx = x - 20 + draw_square(graphic_context, rx, y, 10, (0, 1, 0)) + rx += 10 + 5 + # yellow square + draw_square(graphic_context, rx, y, 12, (1, 1, 0)) + rx += 12 + 5 + # red square + draw_square(graphic_context, rx, y, 14, (1, 0, 0)) + + graphic_context.move_to(x + 50, y + 5) + graphic_context.set_source_rgb(0, 0, 0) + graphic_context.show_text(_("host is a router, switch, or WAP")) + + # connections between hosts + y += 30 + draw_heading(graphic_context, x, y, _("Traceroute connections")) + + y += 20 + graphic_context.move_to(x, y) + graphic_context.show_text(_("Thicker line means higher round-trip time")) + # primary traceroute (blue line) + y += 20 + draw_line(graphic_context, x, y, [], (0, 0, 1), + _("primary traceroute connection")) + # Alternate route (orange line) + y += 20 + draw_line(graphic_context, x, y, [], (1, 0.5, 0), + _("alternate path")) + # no traceroute + y += 20 + draw_line(graphic_context, x, y, [4.0, 2.0], (0, 0, 0), + _("no traceroute information")) + # missing traceroute + y += 20 + graphic_context.set_source_rgb(0.5, 0.7, 0.95) + graphic_context.move_to(x - 15, y) + graphic_context.arc(x - 25, y, 5, 0, 2 * math.pi) + graphic_context.stroke_preserve() + draw_line(graphic_context, x, y, [4.0, 2.0], (0.5, 0.7, 0.95), + _("missing traceroute hop")) + + # special purpose hosts + y += 30 + draw_heading(graphic_context, x, y, _("Additional host icons")) + + # router image + y += 20 + draw_pixmap(graphic_context, x, y, "router", _("router")) + + # switch image + y += 20 + draw_pixmap(graphic_context, x, y, "switch", _("switch")) + + # wap image + y += 20 + draw_pixmap(graphic_context, x, y, "wireless", + _("wireless access point")) + + # firewall image + y += 20 + draw_pixmap(graphic_context, x, y, "firewall", _("firewall")) + + # host with filtered ports + y += 20 + draw_pixmap(graphic_context, x, y, "padlock", + _("host with some filtered ports")) diff --git a/zenmap/radialnet/gui/NodeNotebook.py b/zenmap/radialnet/gui/NodeNotebook.py new file mode 100644 index 0000000..ea208ec --- /dev/null +++ b/zenmap/radialnet/gui/NodeNotebook.py @@ -0,0 +1,742 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk, GObject, Pango + +from radialnet.bestwidgets.boxes import BWVBox, BWHBox, BWScrolledWindow, BWTable +from radialnet.bestwidgets.expanders import BWExpander +from radialnet.bestwidgets.labels import BWLabel, BWSectionLabel +from radialnet.bestwidgets.textview import BWTextEditor +import zenmapCore.I18N # lgtm[py/unused-import] + + +PORTS_HEADER = [ + _('Port'), _('Protocol'), _('State'), _('Service'), _('Method')] +EXTRAPORTS_HEADER = [_('Count'), _('State'), _('Reasons')] + +SERVICE_COLORS = {'open': '#ffd5d5', # noqa + 'closed': '#d5ffd5', # noqa + 'filtered': '#ffffd5', # noqa + 'unfiltered': '#ffd5d5', # noqa + 'open|filtered': '#ffd5d5', # noqa + 'closed|filtered': '#d5ffd5'} # noqa +UNKNOWN_SERVICE_COLOR = '#d5d5d5' + +TRACE_HEADER = ['TTL', 'RTT', 'IP', _('Hostname')] + +TRACE_TEXT = _( + "Traceroute on port <b>%s/%s</b> totalized <b>%d</b> known hops.") + +NO_TRACE_TEXT = _("No traceroute information available.") + +HOP_COLOR = {'known': '#ffffff', # noqa + 'unknown': '#cccccc'} # noqa + +SYSTEM_ADDRESS_TEXT = "[%s] %s" + +OSMATCH_HEADER = ['%', _('Name'), _('DB Line')] +OSCLASS_HEADER = ['%', _('Vendor'), _('Type'), _('Family'), _('Version')] + +USED_PORTS_TEXT = "%d/%s %s" + +TCP_SEQ_NOTE = _("""\ +<b>*</b> TCP sequence <i>index</i> equal to %d and <i>difficulty</i> is "%s".\ +""") + + +def get_service_color(state): + color = SERVICE_COLORS.get(state) + if color is None: + color = UNKNOWN_SERVICE_COLOR + return color + + +class NodeNotebook(Gtk.Notebook): + """ + """ + def __init__(self, node): + """ + """ + Gtk.Notebook.__init__(self) + self.set_tab_pos(Gtk.PositionType.TOP) + + self.__node = node + + self.__create_widgets() + + def __create_widgets(self): + """ + """ + # create body elements + self.__services_page = ServicesPage(self.__node) + self.__system_page = SystemPage(self.__node) + self.__trace_page = TraceroutePage(self.__node) + + # packing notebook elements + self.append_page(self.__system_page, BWLabel(_('General'))) + self.append_page(self.__services_page, BWLabel(_('Services'))) + self.append_page(self.__trace_page, BWLabel(_('Traceroute'))) + + +class ServicesPage(Gtk.Notebook): + """ + """ + def __init__(self, node): + """ + """ + Gtk.Notebook.__init__(self) + self.set_border_width(6) + self.set_tab_pos(Gtk.PositionType.TOP) + + self.__node = node + self.__font = Pango.FontDescription('Monospace') + + self.__create_widgets() + + def __create_widgets(self): + """ + """ + self.__cell = Gtk.CellRendererText() + + # texteditor widgets + self.__texteditor = BWTextEditor() + self.__texteditor.bw_modify_font(self.__font) + self.__texteditor.bw_set_editable(False) + self.__texteditor.set_border_width(0) + + self.__select_combobox = Gtk.ComboBoxText() + self.__select_combobox.connect('changed', self.__change_text_value) + + self.__viewer = BWVBox(spacing=6) + self.__viewer.set_border_width(6) + + self.__viewer.bw_pack_start_noexpand_nofill(self.__select_combobox) + self.__viewer.bw_pack_start_expand_fill(self.__texteditor) + + self.__text = list() + + # ports information + number_of_ports = len(self.__node.get_info('ports')) + self.__ports_label = BWLabel(_('Ports (%s)') % number_of_ports) + + self.__ports_scroll = BWScrolledWindow() + + self.__ports_store = Gtk.TreeStore.new([GObject.TYPE_INT, + GObject.TYPE_STRING, + GObject.TYPE_STRING, + GObject.TYPE_STRING, + GObject.TYPE_STRING, + GObject.TYPE_STRING, + GObject.TYPE_BOOLEAN]) + + self.__ports_treeview = Gtk.TreeView.new_with_model(self.__ports_store) + + for port in self.__node.get_info('ports'): + + color = get_service_color(port['state']['state']) + + service_name = port['service'].get('name', _('<unknown>')) + + service_method = port['service'].get('method', _('<none>')) + + reference = self.__ports_store.append(None, + [port['id'], + port['protocol'], + port['state']['state'], + service_name, + service_method, + color, + True]) + + for key in port['state']: + self.__ports_store.append(reference, + [port['id'], + 'state', + key, + port['state'][key], + '', + 'white', + True]) + + for key in port['service']: + + if key in ['servicefp']: + + text = _('[%d] service: %s') % (port['id'], key) + + self.__select_combobox.append_text(text) + self.__text.append(port['service'][key]) + + value = _('<special field>') + + else: + value = port['service'][key] + + self.__ports_store.append(reference, + [port['id'], + 'service', + key, + value, + '', + 'white', + True]) + + #for script in port['scripts']: + # text = _('[%d] script: %s') % (port['id'], script['id']) + # self.__select_combobox.append_text(text) + # self.__text.append(script['output']) + # + # self.__ports_store.append(reference, + # [port['id'], + # 'script', + # 'id', + # script['id'], + # _('<special field>'), + # 'white', + # True]) + + self.__ports_column = list() + + for i in range(len(PORTS_HEADER)): + + column = Gtk.TreeViewColumn(title=PORTS_HEADER[i], + cell_renderer=self.__cell, + text=i) + + self.__ports_column.append(column) + + self.__ports_column[i].set_reorderable(True) + self.__ports_column[i].set_resizable(True) + self.__ports_column[i].set_sort_column_id(i) + self.__ports_column[i].set_attributes(self.__cell, + text=i, + background=5, + editable=6) + + self.__ports_treeview.append_column(self.__ports_column[i]) + + self.__ports_scroll.add_with_viewport(self.__ports_treeview) + + # extraports information + number_of_xports = 0 + + self.__xports_scroll = BWScrolledWindow() + + self.__xports_store = Gtk.TreeStore.new([GObject.TYPE_INT, + GObject.TYPE_STRING, + GObject.TYPE_STRING, + GObject.TYPE_STRING, + GObject.TYPE_BOOLEAN]) + + self.__xports_treeview = Gtk.TreeView.new_with_model(self.__xports_store) + + for xports in self.__node.get_info('extraports'): + + color = get_service_color(xports['state']) + number_of_xports += xports['count'] + + reference = self.__xports_store.append( + None, [xports['count'], xports['state'], + ", ".join(xports['reason']), color, True]) + + for xreason in xports['all_reason']: + self.__xports_store.append(reference, + [xreason['count'], + xports['state'], + xreason['reason'], + 'white', + True]) + + self.__xports_column = list() + + for i in range(len(EXTRAPORTS_HEADER)): + + column = Gtk.TreeViewColumn(title=EXTRAPORTS_HEADER[i], + cell_renderer=self.__cell, + text=i) + + self.__xports_column.append(column) + + self.__xports_column[i].set_reorderable(True) + self.__xports_column[i].set_resizable(True) + self.__xports_column[i].set_sort_column_id(i) + self.__xports_column[i].set_attributes(self.__cell, + text=i, + background=3, + editable=4) + + self.__xports_treeview.append_column(self.__xports_column[i]) + + xports_label_text = _('Extraports (%s)') % number_of_xports + self.__xports_label = BWLabel(xports_label_text) + + self.__xports_scroll.add_with_viewport(self.__xports_treeview) + + self.append_page(self.__ports_scroll, self.__ports_label) + self.append_page(self.__xports_scroll, self.__xports_label) + self.append_page(self.__viewer, BWLabel(_('Special fields'))) + + if len(self.__text) > 0: + self.__select_combobox.set_active(0) + + def __change_text_value(self, widget): + """ + """ + id = self.__select_combobox.get_active() + + self.__texteditor.bw_set_text(self.__text[id]) + + +class SystemPage(BWScrolledWindow): + """ + """ + def __init__(self, node): + """ + """ + BWScrolledWindow.__init__(self) + + self.__node = node + self.__font = Pango.FontDescription('Monospace') + + self.__create_widgets() + + def __create_widgets(self): + """ + """ + self.__vbox = BWVBox() + self.__vbox.set_border_width(6) + + self.__cell = Gtk.CellRendererText() + + self.__general_frame = BWExpander(_('General information')) + self.__sequences_frame = BWExpander(_('Sequences')) + self.__os_frame = BWExpander(_('Operating System')) + + self.__sequences_frame.bw_add(Gtk.Label.new(_('No sequence information.'))) + self.__os_frame.bw_add(Gtk.Label.new(_('No OS information.'))) + + # general information widgets + self.__general = BWTable(3, 2) + + self.__address_label = BWSectionLabel(_('Address:')) + self.__address_list = Gtk.ComboBoxText.new_with_entry() + self.__address_list.get_child().set_editable(False) + + for address in self.__node.get_info('addresses'): + + params = address['type'], address['addr'] + address_text = SYSTEM_ADDRESS_TEXT % params + + if address['vendor'] is not None and address['vendor'] != '': + address_text += " (%s)" % address['vendor'] + + self.__address_list.append_text(address_text) + + self.__address_list.set_active(0) + + self.__general.bw_attach_next(self.__address_label, + yoptions=Gtk.AttachOptions.FILL, + xoptions=Gtk.AttachOptions.FILL) + self.__general.bw_attach_next(self.__address_list, yoptions=Gtk.AttachOptions.FILL) + + if self.__node.get_info('hostnames') is not None: + + self.__hostname_label = BWSectionLabel(_('Hostname:')) + self.__hostname_list = Gtk.ComboBoxText.new_with_entry() + self.__hostname_list.get_child().set_editable(False) + + for hostname in self.__node.get_info('hostnames'): + + params = hostname['type'], hostname['name'] + self.__hostname_list.append_text(SYSTEM_ADDRESS_TEXT % params) + + self.__hostname_list.set_active(0) + + self.__general.bw_attach_next(self.__hostname_label, + yoptions=Gtk.AttachOptions.FILL, + xoptions=Gtk.AttachOptions.FILL) + self.__general.bw_attach_next(self.__hostname_list, + yoptions=Gtk.AttachOptions.FILL) + + if self.__node.get_info('uptime') is not None: + + self.__uptime_label = BWSectionLabel(_('Last boot:')) + + seconds = self.__node.get_info('uptime')['seconds'] + lastboot = self.__node.get_info('uptime')['lastboot'] + + text = _('%s (%s seconds).') % (lastboot, seconds) + + self.__uptime_value = BWLabel(text) + self.__uptime_value.set_selectable(True) + self.__uptime_value.set_line_wrap(False) + + self.__general.bw_attach_next(self.__uptime_label, + yoptions=Gtk.AttachOptions.FILL, + xoptions=Gtk.AttachOptions.FILL) + self.__general.bw_attach_next(self.__uptime_value, + yoptions=Gtk.AttachOptions.FILL) + + self.__general_frame.bw_add(self.__general) + self.__general_frame.set_expanded(True) + + sequences = self.__node.get_info('sequences') + if len(sequences) > 0: + self.__sequences_frame.bw_add( + self.__create_sequences_widget(sequences)) + + # operating system information widgets + self.__os = Gtk.Notebook() + + os = self.__node.get_info('os') + + if os is not None: + + if 'matches' in os: + + self.__match_scroll = BWScrolledWindow() + + self.__match_store = Gtk.ListStore.new([str, str, int, bool]) + self.__match_treeview = Gtk.TreeView.new_with_model(self.__match_store) + + for os_match in os['matches']: + + self.__match_store.append([os_match['accuracy'], + os_match['name'], + #os_match['db_line'], + 0, # unsupported + True]) + + self.__match_column = list() + + for i in range(len(OSMATCH_HEADER)): + + column = Gtk.TreeViewColumn(title=OSMATCH_HEADER[i], + cell_renderer=self.__cell, + text=i) + + self.__match_column.append(column) + + self.__match_column[i].set_reorderable(True) + self.__match_column[i].set_resizable(True) + self.__match_column[i].set_attributes(self.__cell, + text=i, + editable=3) + + self.__match_column[i].set_sort_column_id(i) + self.__match_treeview.append_column(self.__match_column[i]) + + self.__match_scroll.add_with_viewport(self.__match_treeview) + + self.__os.append_page(self.__match_scroll, BWLabel(_('Match'))) + + if 'classes' in os: + + self.__class_scroll = BWScrolledWindow() + + self.__class_store = Gtk.ListStore.new([str, str, str, str, str, bool]) + self.__class_treeview = Gtk.TreeView.new_with_model(self.__class_store) + + for os_class in os['classes']: + + os_gen = os_class.get('os_gen', '') + + self.__class_store.append([os_class['accuracy'], + os_class['vendor'], + os_class['type'], + os_class['os_family'], + os_gen, + True]) + + self.__class_column = list() + + for i in range(len(OSCLASS_HEADER)): + + column = Gtk.TreeViewColumn(title=OSCLASS_HEADER[i], + cell_renderer=self.__cell, + text=i) + + self.__class_column.append(column) + + self.__class_column[i].set_reorderable(True) + self.__class_column[i].set_resizable(True) + self.__class_column[i].set_attributes(self.__cell, + text=i, + editable=5) + + self.__class_column[i].set_sort_column_id(i) + self.__class_treeview.append_column(self.__class_column[i]) + + self.__class_scroll.add_with_viewport(self.__class_treeview) + + self.__os.append_page(self.__class_scroll, BWLabel(_('Class'))) + + self.__fp_viewer = BWTextEditor() + self.__fp_viewer.bw_modify_font(self.__font) + self.__fp_viewer.bw_set_editable(False) + self.__fp_viewer.bw_set_text(os['fingerprint']) + + self.__fp_ports = BWHBox() + self.__fp_label = BWSectionLabel(_('Used ports:')) + + self.__fp_ports_list = Gtk.ComboBoxText.new_with_entry() + self.__fp_ports_list.get_child().set_editable(False) + + self.__fp_vbox = BWVBox() + + if 'used_ports' in os: + + used_ports = os['used_ports'] + + for port in used_ports: + + params = port['id'], port['protocol'], port['state'] + self.__fp_ports_list.append_text(USED_PORTS_TEXT % params) + + self.__fp_ports_list.set_active(0) + + self.__fp_ports.bw_pack_start_noexpand_nofill(self.__fp_label) + self.__fp_ports.bw_pack_start_expand_fill(self.__fp_ports_list) + + self.__fp_vbox.bw_pack_start_noexpand_nofill(self.__fp_ports) + + self.__os.append_page(self.__fp_viewer, BWLabel(_('Fingerprint'))) + self.__fp_vbox.bw_pack_start_expand_fill(self.__os) + + self.__os_frame.bw_add(self.__fp_vbox) + self.__os_frame.set_expanded(True) + + self.__vbox.bw_pack_start_noexpand_nofill(self.__general_frame) + self.__vbox.bw_pack_start_expand_fill(self.__os_frame) + self.__vbox.bw_pack_start_noexpand_nofill(self.__sequences_frame) + + self.add_with_viewport(self.__vbox) + + def __create_sequences_widget(self, sequences): + """Return a widget representing various OS detection sequences. The + sequences argument is a dict with zero or more of the keys 'tcp', + 'ip_id', and 'tcp_ts'.""" + # sequences information widgets + table = BWTable(5, 3) + + table.attach(BWSectionLabel(_('Class')), 1, 2, 0, 1) + table.attach(BWSectionLabel(_('Values')), 2, 3, 0, 1) + + table.attach(BWSectionLabel('TCP *'), 0, 1, 1, 2) + table.attach(BWSectionLabel('IP ID'), 0, 1, 2, 3) + table.attach(BWSectionLabel(_('TCP Timestamp')), 0, 1, 3, 4) + + tcp = sequences.get('tcp') + if tcp is not None: + tcp_class = BWLabel(tcp['class']) + tcp_class.set_selectable(True) + + table.attach(tcp_class, 1, 2, 1, 2) + + tcp_values = Gtk.ComboBoxText.new_with_entry() + + for value in tcp['values']: + tcp_values.append_text(value) + + tcp_values.set_active(0) + + table.attach(tcp_values, 2, 3, 1, 2) + + tcp_note = BWLabel() + tcp_note.set_selectable(True) + tcp_note.set_line_wrap(False) + tcp_note.set_alignment(1.0, 0.5) + tcp_note.set_markup( + TCP_SEQ_NOTE % (tcp['index'], tcp['difficulty'])) + + table.attach(tcp_note, 0, 3, 4, 5) + + ip_id = sequences.get('ip_id') + if ip_id is not None: + ip_id_class = BWLabel(ip_id['class']) + ip_id_class.set_selectable(True) + + table.attach(ip_id_class, 1, 2, 2, 3) + + ip_id_values = Gtk.ComboBoxText.new_with_entry() + + for value in ip_id['values']: + ip_id_values.append_text(value) + + ip_id_values.set_active(0) + + table.attach(ip_id_values, 2, 3, 2, 3) + + tcp_ts = sequences.get('tcp_ts') + if tcp_ts is not None: + tcp_ts_class = BWLabel(tcp_ts['class']) + tcp_ts_class.set_selectable(True) + + table.attach(tcp_ts_class, 1, 2, 3, 4) + + if tcp_ts['values'] is not None: + + tcp_ts_values = Gtk.ComboBoxText.new_with_entry() + + for value in tcp_ts['values']: + tcp_ts_values.append_text(value) + + tcp_ts_values.set_active(0) + + table.attach(tcp_ts_values, 2, 3, 3, 4) + + return table + + +class TraceroutePage(BWVBox): + """ + """ + def __init__(self, node): + """ + """ + BWVBox.__init__(self) + self.set_border_width(6) + + self.__node = node + + self.__create_widgets() + + def __create_widgets(self): + """ + """ + trace = self.__node.get_info('trace') + hops = None + if trace is not None: + hops = trace.get("hops") + if hops is None or len(hops) == 0: + + self.__trace_label = Gtk.Label.new(NO_TRACE_TEXT) + self.pack_start(self.__trace_label, True, True, 0) + + else: + + # add hops + hops = self.__node.get_info('trace')['hops'] + ttls = [int(i['ttl']) for i in hops] + + self.__cell = Gtk.CellRendererText() + + self.__trace_scroll = BWScrolledWindow() + self.__trace_scroll.set_border_width(0) + + self.__trace_store = Gtk.ListStore.new([int, str, str, str, str, bool]) + self.__trace_treeview = Gtk.TreeView.new_with_model(self.__trace_store) + + count = 0 + + for i in range(1, max(ttls) + 1): + + if i in ttls: + + hop = hops[count] + count += 1 + + self.__trace_store.append([hop['ttl'], + hop['rtt'], + hop['ip'], + hop['hostname'], + HOP_COLOR['known'], + True]) + + else: + self.__trace_store.append([i, + '', + _('<unknown>'), + '', + HOP_COLOR['unknown'], + True]) + + self.__trace_column = list() + + for i in range(len(TRACE_HEADER)): + + column = Gtk.TreeViewColumn(title=TRACE_HEADER[i], + cell_renderer=self.__cell, + text=i) + + self.__trace_column.append(column) + + self.__trace_column[i].set_reorderable(True) + self.__trace_column[i].set_resizable(True) + self.__trace_column[i].set_attributes(self.__cell, + text=i, + background=4, + editable=5) + + self.__trace_treeview.append_column(self.__trace_column[i]) + + self.__trace_column[0].set_sort_column_id(0) + + self.__trace_scroll.add_with_viewport(self.__trace_treeview) + + self.__trace_info = (self.__node.get_info('trace')['port'], + self.__node.get_info('trace')['protocol'], + len(self.__node.get_info('trace')['hops'])) + + self.__trace_label = BWLabel(TRACE_TEXT % self.__trace_info) + self.__trace_label.set_use_markup(True) + + self.bw_pack_start_expand_fill(self.__trace_scroll) + self.bw_pack_start_noexpand_nofill(self.__trace_label) diff --git a/zenmap/radialnet/gui/NodeWindow.py b/zenmap/radialnet/gui/NodeWindow.py new file mode 100644 index 0000000..7c38078 --- /dev/null +++ b/zenmap/radialnet/gui/NodeWindow.py @@ -0,0 +1,129 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk, Gdk, Pango + +import radialnet.util.drawing as drawing + +from radialnet.bestwidgets.windows import BWWindow +from radialnet.bestwidgets.boxes import BWVBox, BWHBox +from radialnet.bestwidgets.labels import BWSectionLabel +from radialnet.gui.Image import Application +from radialnet.gui.NodeNotebook import NodeNotebook + + +DIMENSION_NORMAL = (600, 400) + + +class NodeWindow(BWWindow): + """ + """ + def __init__(self, node, position): + """ + """ + BWWindow.__init__(self, Gtk.WindowType.TOPLEVEL) + self.move(position[0], position[1]) + self.set_default_size(DIMENSION_NORMAL[0], DIMENSION_NORMAL[1]) + + self.__node = node + + self.__title_font = Pango.FontDescription('Monospace Bold') + + self.__icon = Application() + self.__create_widgets() + + def __create_widgets(self): + """ + """ + self.__content = BWVBox() + self.__head = BWHBox(spacing=2) + + self.__notebook = NodeNotebook(self.__node) + + # create head elements + + # icon with node's score color + self.__color_box = Gtk.EventBox() + self.__color_image = Gtk.Image() + self.__color_image.set_from_file(self.__icon.get_icon('border')) + self.__color_box.add(self.__color_image) + self.__color_box.set_size_request(15, 15) + r, g, b = drawing.cairo_to_gdk_color( + self.__node.get_draw_info('color')) + self.__color_box.modify_bg(Gtk.StateType.NORMAL, Gdk.Color(r, g, b)) + + # title with the node ip and hostname + self.__title = self.__node.get_host().get_hostname() + + self.set_title(self.__title) + + self.__title_label = BWSectionLabel(self.__title) + self.__title_label.modify_font(self.__title_font) + + # packing head elements + self.__head.bw_pack_start_noexpand_nofill(self.__color_box) + self.__head.bw_pack_start_expand_fill(self.__title_label) + + # packing all to content + self.__content.bw_pack_start_noexpand_nofill(self.__head) + self.__content.bw_pack_start_expand_fill(self.__notebook) + + # add content to window + self.add(self.__content) diff --git a/zenmap/radialnet/gui/RadialNet.py b/zenmap/radialnet/gui/RadialNet.py new file mode 100644 index 0000000..1a395dd --- /dev/null +++ b/zenmap/radialnet/gui/RadialNet.py @@ -0,0 +1,2020 @@ +# vim: set encoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk, GLib, Gdk + +import math +import cairo + +from functools import reduce + +import radialnet.util.geometry as geometry +import radialnet.util.misc as misc + +from radialnet.core.Coordinate import PolarCoordinate, CartesianCoordinate +from radialnet.core.Interpolation import Linear2DInterpolator +from radialnet.core.Graph import Node +from radialnet.gui.NodeWindow import NodeWindow +from radialnet.gui.Image import Icons, get_pixels_for_cairo_image_surface + +REGION_COLORS = [(1.0, 0.0, 0.0), (1.0, 1.0, 0.0), (0.0, 1.0, 0.0)] +REGION_RED = 0 +REGION_YELLOW = 1 +REGION_GREEN = 2 + +SQUARE_TYPES = ['router', 'switch', 'wap'] + +ICON_DICT = {'router': 'router', + 'switch': 'switch', + 'wap': 'wireless', + 'firewall': 'firewall'} + +POINTER_JUMP_TO = 0 +POINTER_INFO = 1 +POINTER_GROUP = 2 +POINTER_FILL = 3 + +LAYOUT_SYMMETRIC = 0 +LAYOUT_WEIGHTED = 1 + +INTERPOLATION_CARTESIAN = 0 +INTERPOLATION_POLAR = 1 + +FILE_TYPE_PDF = 1 +FILE_TYPE_PNG = 2 +FILE_TYPE_PS = 3 +FILE_TYPE_SVG = 4 + + +class RadialNet(Gtk.DrawingArea): + """ + Radial network visualization widget + """ + def __init__(self, layout=LAYOUT_SYMMETRIC): + """ + Constructor method of RadialNet widget class + @type number_of_rings: number + @param number_of_rings: Number of rings in radial layout + """ + self.__center_of_widget = (0, 0) + self.__graph = None + + self.__number_of_rings = 0 + self.__ring_gap = 30 + self.__min_ring_gap = 10 + + self.__layout = layout + self.__interpolation = INTERPOLATION_POLAR + self.__interpolation_slow_in_out = True + + self.__animating = False + self.__animation_rate = 1000 // 60 # 60Hz (human perception factor) + self.__number_of_frames = 60 + + self.__scale = 1.0 + # rotated so that single-host traceroute doesn't have overlapping hosts + self.__rotate = 225 + self.__translation = (0, 0) + + self.__button1_press = False + self.__button2_press = False + self.__button3_press = False + + self.__last_motion_point = None + + self.__fisheye = False + self.__fisheye_ring = 0 + self.__fisheye_spread = 0.5 + self.__fisheye_interest = 2 + + self.__show_address = True + self.__show_hostname = True + self.__show_icon = True + self.__show_latency = False + self.__show_ring = True + self.__show_region = True + self.__region_color = REGION_RED + + self.__node_views = dict() + self.__last_group_node = None + + self.__pointer_status = POINTER_JUMP_TO + + self.__sorted_nodes = list() + + self.__icon = Icons() + + super(RadialNet, self).__init__() + + self.connect('draw', self.draw) + self.connect('button_press_event', self.button_press) + self.connect('button_release_event', self.button_release) + self.connect('motion_notify_event', self.motion_notify) + self.connect('enter_notify_event', self.enter_notify) + self.connect('leave_notify_event', self.leave_notify) + self.connect('key_press_event', self.key_press) + self.connect('key_release_event', self.key_release) + self.connect('scroll_event', self.scroll_event) + + self.add_events(Gdk.EventMask.BUTTON_PRESS_MASK | + Gdk.EventMask.BUTTON_RELEASE_MASK | + Gdk.EventMask.ENTER_NOTIFY_MASK | + Gdk.EventMask.LEAVE_NOTIFY_MASK | + Gdk.EventMask.KEY_PRESS_MASK | + Gdk.EventMask.KEY_RELEASE_MASK | + Gdk.EventMask.POINTER_MOTION_HINT_MASK | + Gdk.EventMask.POINTER_MOTION_MASK | + Gdk.EventMask.SCROLL_MASK) + + self.set_can_focus(True) + self.grab_focus() + + def graph_is_not_empty(function): + """ + Decorator function to prevent the execution when graph not is set + @type function: function + @param function: Protected function + """ + def check_graph_status(*args): + if args[0].__graph is None: + return False + return function(*args) + + return check_graph_status + + def not_is_in_animation(function): + """ + Decorator function to prevent the execution when graph is animating + @type function: function + @param function: Protected function + """ + def check_animation_status(*args): + if args[0].__animating: + return False + return function(*args) + + return check_animation_status + + def save_drawing_to_file(self, file, type=FILE_TYPE_PNG): + """ + """ + allocation = self.get_allocation() + + if type == FILE_TYPE_PDF: + self.surface = cairo.PDFSurface(file, + allocation.width, + allocation.height) + elif type == FILE_TYPE_PNG: + self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, + allocation.width, + allocation.height) + elif type == FILE_TYPE_PS: + self.surface = cairo.PSSurface(file, + allocation.width, + allocation.height) + elif type == FILE_TYPE_SVG: + self.surface = cairo.SVGSurface(file, + allocation.width, + allocation.height) + else: + raise TypeError('unknown surface type') + + context = cairo.Context(self.surface) + + context.rectangle(0, 0, allocation.width, allocation.height) + context.set_source_rgb(1.0, 1.0, 1.0) + context.fill() + + self.__draw(context) + + if type == FILE_TYPE_PNG: + self.surface.write_to_png(file) + + self.surface.flush() + self.surface.finish() + + return True + + def get_slow_inout(self): + """ + """ + return self.__interpolation_slow_in_out + + def set_slow_inout(self, value): + """ + """ + self.__interpolation_slow_in_out = value + + def get_region_color(self): + """ + """ + return self.__region_color + + def set_region_color(self, value): + """ + """ + self.__region_color = value + + def get_show_region(self): + """ + """ + return self.__show_region + + def set_show_region(self, value): + """ + """ + self.__show_region = value + self.queue_draw() + + def get_pointer_status(self): + """ + """ + return self.__pointer_status + + def set_pointer_status(self, pointer_status): + """ + """ + self.__pointer_status = pointer_status + + def get_show_address(self): + """ + """ + return self.__show_address + + def get_show_hostname(self): + """ + """ + return self.__show_hostname + + def get_show_ring(self): + """ + """ + return self.__show_ring + + def set_show_address(self, value): + """ + """ + self.__show_address = value + self.queue_draw() + + def set_show_hostname(self, value): + """ + """ + self.__show_hostname = value + self.queue_draw() + + def set_show_ring(self, value): + """ + """ + self.__show_ring = value + self.queue_draw() + + def get_min_ring_gap(self): + """ + """ + return self.__min_ring_gap + + @graph_is_not_empty + @not_is_in_animation + def set_min_ring_gap(self, value): + """ + """ + self.__min_ring_gap = int(value) + + if self.__ring_gap < self.__min_ring_gap: + self.__ring_gap = self.__min_ring_gap + + self.__update_nodes_positions() + self.queue_draw() + + return True + + def get_number_of_frames(self): + """ + """ + return self.__number_of_frames + + @not_is_in_animation + def set_number_of_frames(self, number_of_frames): + """ + """ + if number_of_frames > 2: + + self.__number_of_frames = int(number_of_frames) + return True + + self.__number_of_frames = 3 + return False + + @not_is_in_animation + def update_layout(self): + """ + """ + if self.__graph is None: + return + self.__animating = True + self.__calc_interpolation(self.__graph.get_main_node()) + self.__livens_up() + + @not_is_in_animation + def set_layout(self, layout): + """ + """ + if self.__layout != layout: + + self.__layout = layout + + if self.__graph is not None: + + self.__animating = True + self.__calc_interpolation(self.__graph.get_main_node()) + self.__livens_up() + + return True + + return False + + def get_layout(self): + """ + """ + return self.__layout + + @not_is_in_animation + def set_interpolation(self, interpolation): + """ + """ + self.__interpolation = interpolation + + return True + + def get_interpolation(self): + """ + """ + return self.__interpolation + + def get_number_of_rings(self): + """ + """ + return self.__number_of_rings + + def get_fisheye_ring(self): + """ + """ + return self.__fisheye_ring + + def get_fisheye_interest(self): + """ + """ + return self.__fisheye_interest + + def get_fisheye_spread(self): + """ + """ + return self.__fisheye_spread + + def get_fisheye(self): + """ + """ + return self.__fisheye + + def set_fisheye(self, enable): + """ + """ + self.__fisheye = enable + + self.__update_nodes_positions() + self.queue_draw() + + def set_fisheye_ring(self, value): + """ + """ + self.__fisheye_ring = value + self.__check_fisheye_ring() + + self.__update_nodes_positions() + self.queue_draw() + + def set_fisheye_interest(self, value): + """ + """ + self.__fisheye_interest = value + + self.__update_nodes_positions() + self.queue_draw() + + def set_fisheye_spread(self, value): + """ + """ + self.__fisheye_spread = value + + self.__update_nodes_positions() + self.queue_draw() + + def get_show_icon(self): + """ + """ + return self.__show_icon + + def set_show_icon(self, value): + """ + """ + self.__show_icon = value + self.queue_draw() + + def get_show_latency(self): + """ + """ + return self.__show_latency + + def set_show_latency(self, value): + """ + """ + self.__show_latency = value + self.queue_draw() + + def get_scale(self): + """ + """ + return self.__scale + + def get_zoom(self): + """ + """ + return int(round(self.__scale * 100)) + + def set_scale(self, scale): + """ + """ + if scale >= 0.01: + + self.__scale = scale + self.queue_draw() + + def set_zoom(self, zoom): + """ + """ + if float(zoom) >= 1: + + self.set_scale(float(zoom) / 100.0) + self.queue_draw() + + def get_ring_gap(self): + """ + """ + return self.__ring_gap + + @not_is_in_animation + def set_ring_gap(self, ring_gap): + """ + """ + if ring_gap >= self.__min_ring_gap: + + self.__ring_gap = ring_gap + self.__update_nodes_positions() + self.queue_draw() + + def scroll_event(self, widget, event): + """ + """ + if event.direction == Gdk.ScrollDirection.UP: + self.set_scale(self.__scale + 0.01) + + if event.direction == Gdk.ScrollDirection.DOWN: + self.set_scale(self.__scale - 0.01) + + self.queue_draw() + + @graph_is_not_empty + @not_is_in_animation + def key_press(self, widget, event): + """ + """ + key = Gdk.keyval_name(event.keyval) + + if key == 'KP_Add': + self.set_ring_gap(self.__ring_gap + 1) + + elif key == 'KP_Subtract': + self.set_ring_gap(self.__ring_gap - 1) + + elif key == 'Page_Up': + self.set_scale(self.__scale + 0.01) + + elif key == 'Page_Down': + self.set_scale(self.__scale - 0.01) + + self.queue_draw() + + return True + + @graph_is_not_empty + def key_release(self, widget, event): + """ + """ + key = Gdk.keyval_name(event.keyval) + + if key == 'c': + self.__translation = (0, 0) + + elif key == 'r': + self.__show_ring = not self.__show_ring + + elif key == 'a': + self.__show_address = not self.__show_address + + elif key == 'h': + self.__show_hostname = not self.__show_hostname + + elif key == 'i': + self.__show_icon = not self.__show_icon + + elif key == 'l': + self.__show_latency = not self.__show_latency + + self.queue_draw() + + return True + + @graph_is_not_empty + @not_is_in_animation + def enter_notify(self, widget, event): + """ + """ + self.grab_focus() + return False + + @graph_is_not_empty + @not_is_in_animation + def leave_notify(self, widget, event): + """ + """ + for node in self.__graph.get_nodes(): + node.set_draw_info({'over': False}) + + self.queue_draw() + + return False + + @graph_is_not_empty + def button_press(self, widget, event): + """ + Drawing callback + @type widget: GtkWidget + @param widget: Gtk widget superclass + @type event: GtkEvent + @param event: Gtk event of widget + @rtype: boolean + @return: Indicator of the event propagation + """ + result = self.__get_node_by_coordinate(self.get_pointer()) + + if event.button == 1: + self.__button1_press = True + + # animate if node is pressed + if self.__pointer_status == POINTER_JUMP_TO and event.button == 1: + + # prevent double animation + if self.__animating: + return False + + if result is not None: + + node, point = result + main_node = self.__graph.get_main_node() + + if node != main_node: + + if node.get_draw_info('group'): + + node.set_draw_info({'group': False}) + node.set_subtree_info({'grouped': False, + 'group_node': None}) + + self.__animating = True + self.__calc_interpolation(node) + self.__livens_up() + + # group node if it's pressed + elif self.__pointer_status == POINTER_GROUP and event.button == 1: + + # prevent group on animation + if self.__animating: + return False + + if result is not None: + + node, point = result + main_node = self.__graph.get_main_node() + + if node != main_node: + + if node.get_draw_info('group'): + + node.set_draw_info({'group': False}) + node.set_subtree_info({'grouped': False, + 'group_node': None}) + + else: + + self.__last_group_node = node + + node.set_draw_info({'group': True}) + node.set_subtree_info({'grouped': True, + 'group_node': node}) + + self.__animating = True + self.__calc_interpolation(self.__graph.get_main_node()) + self.__livens_up() + + # setting to show node's region + elif self.__pointer_status == POINTER_FILL and event.button == 1: + + if result is not None: + + node, point = result + + if node.get_draw_info('region') == self.__region_color: + node.set_draw_info({'region': None}) + + else: + node.set_draw_info({'region': self.__region_color}) + + self.queue_draw() + + # show node details + elif event.button == 3 or self.__pointer_status == POINTER_INFO: + + if event.button == 3: + self.__button3_press = True + + if result is not None: + + # first returned value is not meaningful and should be ignored + _, xw, yw = self.get_window().get_origin() + node, point = result + x, y = point + + if node in self.__node_views.keys(): + + self.__node_views[node].present() + + elif node.get_draw_info('scanned'): + + view = NodeWindow(node, (int(xw + x), int(yw + y))) + + def close_view(view, event, node): + view.destroy() + del self.__node_views[node] + + view.connect("delete-event", close_view, node) + view.show_all() + self.__node_views[node] = view + + return False + + @graph_is_not_empty + def button_release(self, widget, event): + """ + Drawing callback + @type widget: GtkWidget + @param widget: Gtk widget superclass + @type event: GtkEvent + @param event: Gtk event of widget + @rtype: boolean + @return: Indicator of the event propagation + """ + if event.button == 1: + self.__button1_press = False + + if event.button == 2: + self.__button2_press = False + + if event.button == 3: + self.__button3_press = False + + self.grab_focus() + + return False + + @graph_is_not_empty + def motion_notify(self, widget, event): + """ + Drawing callback + @type widget: GtkWidget + @param widget: Gtk widget superclass + @type event: GtkEvent + @param event: Gtk event of widget + @rtype: boolean + @return: Indicator of the event propagation + """ + pointer = self.get_pointer() + + for node in self.__graph.get_nodes(): + node.set_draw_info({'over': False}) + + result = self.__get_node_by_coordinate(self.get_pointer()) + + if result is not None: + result[0].set_draw_info({'over': True}) + + elif self.__button1_press and self.__last_motion_point is not None: + + ax, ay = pointer + ox, oy = self.__last_motion_point + tx, ty = self.__translation + + self.__translation = (tx + ax - ox, ty - ay + oy) + + self.__last_motion_point = pointer + + self.grab_focus() + self.queue_draw() + + return False + + def draw(self, widget, context): + """ + Drawing callback + @type widget: GtkWidget + @param widget: Gtk widget superclass + @type context: cairo.Context + @param context: cairo context class + @rtype: boolean + @return: Indicator of the event propagation + """ + context.set_source_rgb(1.0, 1.0, 1.0) + context.fill() + + self.__draw(context) + + return False + + @graph_is_not_empty + def __draw(self, context): + """ + Drawing method + """ + # getting allocation reference + allocation = self.get_allocation() + + self.__center_of_widget = (allocation.width // 2, + allocation.height // 2) + + xc, yc = self.__center_of_widget + + ax, ay = self.__translation + + # xc = 320 yc = 240 + + # -1.5 | -0.5 ( 480, 360) + # -1.0 | 0.0 ( 320, 240) + # -0.5 | 0.5 ( 160, 120) + # 0.0 | 1.0 ( 0, 0) + # 0.5 | 1.5 (-160, -120) + # 1.0 | 2.0 (-320, -240) + # 1.5 | 2.5 (-480, -360) + + # scaling and translate + factor = -(self.__scale - 1) + + context.translate(xc * factor + ax, yc * factor - ay) + + if self.__scale != 1.0: + context.scale(self.__scale, self.__scale) + + # drawing over node's region + if self.__show_region and not self.__animating: + + for node in self.__sorted_nodes: + + not_grouped = not node.get_draw_info('grouped') + + if node.get_draw_info('region') is not None and not_grouped: + + xc, yc = self.__center_of_widget + r, g, b = REGION_COLORS[node.get_draw_info('region')] + + start, final = node.get_draw_info('range') + + i_radius = node.get_coordinate_radius() + f_radius = self.__calc_radius(self.__number_of_rings - 1) + + is_fill_all = abs(final - start) == 360 + + final = math.radians(final + self.__rotate) + start = math.radians(start + self.__rotate) + + context.move_to(xc, yc) + context.set_source_rgba(r, g, b, 0.1) + context.new_path() + context.arc(xc, yc, i_radius, -final, -start) + context.arc_negative(xc, yc, f_radius, -start, -final) + context.close_path() + context.fill() + context.stroke() + + if not is_fill_all: + + context.set_source_rgb(r, g, b) + context.set_line_width(1) + + xa, ya = PolarCoordinate( + i_radius, final).to_cartesian() + xb, yb = PolarCoordinate( + f_radius, final).to_cartesian() + + context.move_to(xc + xa, yc - ya) + context.line_to(xc + xb, yc - yb) + context.stroke() + + xa, ya = PolarCoordinate( + i_radius, start).to_cartesian() + xb, yb = PolarCoordinate( + f_radius, start).to_cartesian() + + context.move_to(xc + xa, yc - ya) + context.line_to(xc + xb, yc - yb) + context.stroke() + + # drawing network rings + if self.__show_ring and not self.__animating: + + for i in range(1, self.__number_of_rings): + + radius = self.__calc_radius(i) + + context.arc(xc, yc, radius, 0, 2 * math.pi) + context.set_source_rgb(0.8, 0.8, 0.8) + context.set_line_width(1) + context.stroke() + + # drawing nodes and your connections + for edge in self.__graph.get_edges(): + + # check group constraints for edges + a, b = edge.get_nodes() + + a_is_grouped = a.get_draw_info('grouped') + b_is_grouped = b.get_draw_info('grouped') + + a_is_group = a.get_draw_info('group') + b_is_group = b.get_draw_info('group') + + a_group = a.get_draw_info('group_node') + b_group = b.get_draw_info('group_node') + + a_is_child = a in b.get_draw_info('children') + b_is_child = b in a.get_draw_info('children') + + last_group = self.__last_group_node + groups = [a_group, b_group] + + if last_group in groups and last_group is not None: + self.__draw_edge(context, edge) + + elif not a_is_grouped or not b_is_grouped: + + if not (a_is_group and b_is_child or + b_is_group and a_is_child): + self.__draw_edge(context, edge) + + elif a_group != b_group: + self.__draw_edge(context, edge) + + for node in reversed(self.__sorted_nodes): + + # check group constraints for nodes + group = node.get_draw_info('group_node') + grouped = node.get_draw_info('grouped') + + if group == self.__last_group_node or not grouped: + self.__draw_node(context, node) + + def __draw_edge(self, context, edge): + """ + Draw the connection between two nodes + @type : Edge + @param : The second node that will be connected + """ + a, b = edge.get_nodes() + + xa, ya = a.get_cartesian_coordinate() + xb, yb = b.get_cartesian_coordinate() + xc, yc = self.__center_of_widget + + a_children = a.get_draw_info('children') + b_children = b.get_draw_info('children') + + latency = edge.get_weights_mean() + + # check if isn't an hierarchy connection + if a not in b_children and b not in a_children: + context.set_source_rgba(1.0, 0.6, 0.1, 0.8) + + elif a.get_draw_info('no_route') or b.get_draw_info('no_route'): + context.set_source_rgba(0.0, 0.0, 0.0, 0.8) + + else: + context.set_source_rgba(0.1, 0.5, 1.0, 0.8) + + # calculating line thickness by latency + if latency is not None: + + min = self.__graph.get_min_edge_mean_weight() + max = self.__graph.get_max_edge_mean_weight() + + if max != min: + thickness = (latency - min) * 4 / (max - min) + 1 + + else: + thickness = 1 + + context.set_line_width(thickness) + + else: + + context.set_dash([2, 2]) + context.set_line_width(1) + + context.move_to(xc + xa, yc - ya) + context.line_to(xc + xb, yc - yb) + context.stroke() + + context.set_dash([1, 0]) + + if not self.__animating and self.__show_latency: + + if latency is not None: + + context.set_font_size(8) + context.set_line_width(1) + context.move_to(xc + (xa + xb) / 2 + 1, + yc - (ya + yb) / 2 + 4) + context.show_text(str(round(latency, 2))) + context.stroke() + + def __draw_node(self, context, node): + """ + Draw nodes and your information + @type : NetNode + @param : The node to be drawn + """ + x, y = node.get_cartesian_coordinate() + xc, yc = self.__center_of_widget + r, g, b = node.get_draw_info('color') + radius = node.get_draw_info('radius') + + type = node.get_info('device_type') + + x_gap = radius + 2 + y_gap = 0 + + # draw group indication + if node.get_draw_info('group'): + + x_gap += 5 + + if type in SQUARE_TYPES: + context.rectangle(xc + x - radius - 5, + yc - y - radius - 5, + 2 * radius + 10, + 2 * radius + 10) + + else: + context.arc(xc + x, yc - y, radius + 5, 0, 2 * math.pi) + + context.set_source_rgb(1.0, 1.0, 1.0) + context.fill_preserve() + + if node.deep_search_child(self.__graph.get_main_node()): + context.set_source_rgb(0.0, 0.0, 0.0) + + else: + context.set_source_rgb(0.1, 0.5, 1.0) + + context.set_line_width(2) + context.stroke() + + # draw over node + if node.get_draw_info('over'): + + context.set_line_width(0) + + if type in SQUARE_TYPES: + context.rectangle(xc + x - radius - 5, + yc - y - radius - 5, + 2 * radius + 10, + 2 * radius + 10) + + else: + context.arc(xc + x, yc - y, radius + 5, 0, 2 * math.pi) + + context.set_source_rgb(0.1, 0.5, 1.0) + context.fill_preserve() + context.stroke() + + # draw node + if type in SQUARE_TYPES: + context.rectangle(xc + x - radius, + yc - y - radius, + 2 * radius, + 2 * radius) + + else: + context.arc(xc + x, yc - y, radius, 0, 2 * math.pi) + + # draw icons + if not self.__animating and self.__show_icon: + + icons = list() + + if type in ICON_DICT.keys(): + icons.append(self.__icon.get_pixbuf(ICON_DICT[type])) + + if node.get_info('filtered'): + icons.append(self.__icon.get_pixbuf('padlock')) + + for icon in icons: + + stride, data = get_pixels_for_cairo_image_surface(icon) + + # Cairo documentation says that the correct way to obtain a + # legal stride value is using the function + # cairo.ImageSurface.format_stride_for_width(). + # But this method is only available since cairo 1.6. So we are + # using the stride returned by + # get_pixels_for_cairo_image_surface() function. + surface = cairo.ImageSurface.create_for_data(data, + cairo.FORMAT_ARGB32, + icon.get_width(), + icon.get_height(), + stride) + + context.set_source_surface(surface, + round(xc + x + x_gap), + round(yc - y + y_gap - 6)) + context.paint() + + x_gap += 13 + + # draw node text + context.set_source_rgb(r, g, b) + context.fill_preserve() + + if node.get_draw_info('valid'): + context.set_source_rgb(0.0, 0.0, 0.0) + + else: + context.set_source_rgb(0.1, 0.5, 1.0) + + if not self.__animating and self.__show_address: + + context.set_font_size(8) + context.move_to(round(xc + x + x_gap), + round(yc - y + y_gap + 4)) + + hostname = node.get_info('hostname') + + if hostname is not None and self.__show_hostname: + context.show_text(hostname) + + elif node.get_info('ip') is not None: + context.show_text(node.get_info('ip')) + + context.set_line_width(1) + context.stroke() + + def __check_fisheye_ring(self): + """ + """ + if self.__fisheye_ring >= self.__number_of_rings: + self.__fisheye_ring = self.__number_of_rings - 1 + + def __set_number_of_rings(self, value): + """ + """ + self.__number_of_rings = value + self.__check_fisheye_ring() + + def __fisheye_function(self, ring): + """ + """ + distance = abs(self.__fisheye_ring - ring) + level_of_detail = self.__ring_gap * self.__fisheye_interest + spread_distance = distance - distance * self.__fisheye_spread + + value = level_of_detail / (spread_distance + 1) + + if value < self.__min_ring_gap: + value = self.__min_ring_gap + + return value + + @graph_is_not_empty + @not_is_in_animation + def __update_nodes_positions(self): + """ + """ + for node in self.__sorted_nodes: + + if node.get_draw_info('grouped'): + + # deep group check + group = node.get_draw_info('group_node') + + while group.get_draw_info('group_node') is not None: + group = group.get_draw_info('group_node') + + ring = group.get_draw_info('ring') + node.set_coordinate_radius(self.__calc_radius(ring)) + + else: + ring = node.get_draw_info('ring') + node.set_coordinate_radius(self.__calc_radius(ring)) + + @graph_is_not_empty + def __get_node_by_coordinate(self, point): + """ + """ + xc, yc = self.__center_of_widget + + for node in self.__graph.get_nodes(): + + if node.get_draw_info('grouped'): + continue + + ax, ay = self.__translation + + xn, yn = node.get_cartesian_coordinate() + center = (xc + xn * self.__scale + ax, yc - yn * self.__scale - ay) + radius = node.get_draw_info('radius') * self.__scale + + type = node.get_info('device_type') + + if type in SQUARE_TYPES: + if geometry.is_in_square(point, radius, center): + return node, center + + else: + if geometry.is_in_circle(point, radius, center): + return node, center + + return None + + def __calc_radius(self, ring): + """ + """ + if self.__fisheye: + + radius = 0 + + while ring > 0: + + radius += self.__fisheye_function(ring) + ring -= 1 + + else: + radius = ring * self.__ring_gap + + return radius + + @graph_is_not_empty + def __arrange_nodes(self): + """ + """ + new_nodes = set([self.__graph.get_main_node()]) + old_nodes = set() + + number_of_needed_rings = 1 + ring = 0 + + # while new nodes were found + while len(new_nodes) > 0: + + tmp_nodes = set() + + # for each new nodes + for node in new_nodes: + + old_nodes.add(node) + + # set ring location + node.set_draw_info({'ring': ring}) + + # check group constraints + if (node.get_draw_info('group') or + node.get_draw_info('grouped')): + children = node.get_draw_info('children') + + else: + + # getting connections and fixing multiple fathers + children = set() + for child in self.__graph.get_node_connections(node): + if child in old_nodes or child in new_nodes: + continue + if child.get_draw_info('grouped'): + continue + children.add(child) + + # setting father foreign + for child in children: + child.set_draw_info({'father': node}) + + node.set_draw_info( + {'children': misc.sort_children(children, node)}) + tmp_nodes.update(children) + + # check group influence in number of rings + for node in tmp_nodes: + + if not node.get_draw_info('grouped'): + + number_of_needed_rings += 1 + break + + # update new nodes set + new_nodes.update(tmp_nodes) + new_nodes.difference_update(old_nodes) + + ring += 1 + + self.__set_number_of_rings(number_of_needed_rings) + + def __weighted_layout(self): + """ + """ + # calculating the space needed by each node + self.__graph.get_main_node().set_draw_info({'range': (0, 360)}) + new_nodes = set([self.__graph.get_main_node()]) + + self.__graph.get_main_node().calc_needed_space() + + while len(new_nodes) > 0: + + node = new_nodes.pop() + + # add only no grouped nodes + children = set() + for child in node.get_draw_info('children'): + + if not child.get_draw_info('grouped'): + children.add(child) + new_nodes.add(child) + + if len(children) > 0: + + min, max = node.get_draw_info('range') + + node_total = max - min + children_need = node.get_draw_info('children_need') + + for child in children: + + child_need = child.get_draw_info('space_need') + child_total = node_total * child_need / children_need + + theta = child_total / 2 + min + self.__rotate + + child.set_coordinate_theta(theta) + child.set_draw_info({'range': (min, min + child_total)}) + + min += child_total + + def __symmetric_layout(self): + """ + """ + self.__graph.get_main_node().set_draw_info({'range': (0, 360)}) + new_nodes = set([self.__graph.get_main_node()]) + + while len(new_nodes) > 0: + + node = new_nodes.pop() + + # add only no grouped nodes + children = set() + for child in node.get_draw_info('children'): + + if not child.get_draw_info('grouped'): + children.add(child) + new_nodes.add(child) + + if len(children) > 0: + + min, max = node.get_draw_info('range') + factor = float(max - min) / len(children) + + for child in children: + + theta = factor / 2 + min + self.__rotate + + child.set_coordinate_theta(theta) + child.set_draw_info({'range': (min, min + factor)}) + + min += factor + + @graph_is_not_empty + def __calc_layout(self, reference): + """ + """ + # selecting layout algorithm + if self.__layout == LAYOUT_SYMMETRIC: + self.__symmetric_layout() + + elif self.__layout == LAYOUT_WEIGHTED: + self.__weighted_layout() + + # rotating focus' children to keep orientation + if reference is not None: + + father, angle = reference + theta = father.get_coordinate_theta() + factor = theta - angle + + for node in self.__graph.get_nodes(): + + theta = node.get_coordinate_theta() + node.set_coordinate_theta(theta - factor) + + a, b = node.get_draw_info('range') + node.set_draw_info({'range': (a - factor, b - factor)}) + + @graph_is_not_empty + def __calc_node_positions(self, reference=None): + """ + """ + # set nodes' hierarchy + self.__arrange_nodes() + self.calc_sorted_nodes() + + # set nodes' coordinate radius + for node in self.__graph.get_nodes(): + + ring = node.get_draw_info('ring') + node.set_coordinate_radius(self.__calc_radius(ring)) + + # set nodes' coordinate theta + self.__calc_layout(reference) + + def __calc_interpolation(self, focus): + """ + """ + old_main_node = self.__graph.get_main_node() + self.__graph.set_main_node(focus) + + # getting initial coordinates + for node in self.__graph.get_nodes(): + + if self.__interpolation == INTERPOLATION_POLAR: + coordinate = node.get_polar_coordinate() + + elif self.__interpolation == INTERPOLATION_CARTESIAN: + coordinate = node.get_cartesian_coordinate() + + node.set_draw_info({'start_coordinate': coordinate}) + + father = focus.get_draw_info('father') + + # calculate nodes positions (and father orientation)? + if father is not None: + + xa, ya = father.get_cartesian_coordinate() + xb, yb = focus.get_cartesian_coordinate() + + angle = math.atan2(yb - ya, xb - xa) + angle = math.degrees(angle) + + self.__calc_node_positions((father, 180 + angle)) + + else: + self.__calc_node_positions() + + # steps for slow-in/slow-out animation + steps = list(range(self.__number_of_frames)) + + for i in range(len(steps) // 2): + steps[self.__number_of_frames - 1 - i] = steps[i] + + # normalize angles and calculate interpolated points + for node in self.__sorted_nodes: + + l2di = Linear2DInterpolator() + + # change grouped nodes coordinate + if node.get_draw_info('grouped'): + + group_node = node.get_draw_info('group_node') + a, b = group_node.get_draw_info('final_coordinate') + + if self.__interpolation == INTERPOLATION_POLAR: + node.set_polar_coordinate(a, b) + + elif self.__interpolation == INTERPOLATION_CARTESIAN: + node.set_cartesian_coordinate(a, b) + + # change interpolation method + if self.__interpolation == INTERPOLATION_POLAR: + + coordinate = node.get_polar_coordinate() + node.set_draw_info({'final_coordinate': coordinate}) + + # adjusting polar coordinates + ri, ti = node.get_draw_info('start_coordinate') + rf, tf = node.get_draw_info('final_coordinate') + + # normalization [0, 360] + ti = geometry.normalize_angle(ti) + tf = geometry.normalize_angle(tf) + + # against longest path + ti, tf = geometry.calculate_short_path(ti, tf) + + # main node goes direct to center (no arc) + if node == self.__graph.get_main_node(): + tf = ti + + # old main node goes direct to new position (no arc) + if node == old_main_node: + ti = tf + + node.set_draw_info({'start_coordinate': (ri, ti)}) + node.set_draw_info({'final_coordinate': (rf, tf)}) + + elif self.__interpolation == INTERPOLATION_CARTESIAN: + + coordinate = node.get_cartesian_coordinate() + node.set_draw_info({'final_coordinate': coordinate}) + + # calculate interpolated points + ai, bi = node.get_draw_info('start_coordinate') + af, bf = node.get_draw_info('final_coordinate') + + l2di.set_start_point(ai, bi) + l2di.set_final_point(af, bf) + + if self.__interpolation_slow_in_out: + points = l2di.get_weighed_points( + self.__number_of_frames, steps) + + else: + points = l2di.get_points(self.__number_of_frames) + + node.set_draw_info({'interpolated_coordinate': points}) + + return True + + def __livens_up(self, index=0): + """ + """ + if self.__graph is None: + # Bail out if the graph became empty during an animation. + self.__last_group_node = None + self.__animating = False + return False + + # prepare interpolated points + if index == 0: + + # prevent unnecessary animation + no_need_to_move = True + + for node in self.__graph.get_nodes(): + + ai, bi = node.get_draw_info('start_coordinate') + af, bf = node.get_draw_info('final_coordinate') + + start_c = round(ai), round(bi) + final_c = round(af), round(bf) + + if start_c != final_c: + no_need_to_move = False + + if no_need_to_move: + + self.__animating = False + return False + + # move all nodes for pass 'index' + for node in self.__graph.get_nodes(): + + a, b = node.get_draw_info('interpolated_coordinate')[index] + + if self.__interpolation == INTERPOLATION_POLAR: + node.set_polar_coordinate(a, b) + + elif self.__interpolation == INTERPOLATION_CARTESIAN: + node.set_cartesian_coordinate(a, b) + + self.queue_draw() + + # animation continue condition + if index < self.__number_of_frames - 1: + GLib.timeout_add(self.__animation_rate, # time to recall + self.__livens_up, # recursive call + index + 1) # next iteration + else: + self.__last_group_node = None + self.__animating = False + + return False + + @not_is_in_animation + def set_graph(self, graph): + """ + Set graph to be displayed in layout + @type : Graph + @param : Set the graph used in visualization + """ + if graph.get_number_of_nodes() > 0: + + self.__graph = graph + + self.__calc_node_positions() + self.queue_draw() + + else: + self.__graph = None + + def get_scanned_nodes(self): + """ + """ + nodes = list() + if self.__graph is None: + return nodes + + for node in self.__graph.get_nodes(): + + if node.get_draw_info('scanned'): + nodes.append(node) + + return nodes + + def get_graph(self): + """ + """ + return self.__graph + + def set_empty(self): + """ + """ + del(self.__graph) + self.__graph = None + + self.queue_draw() + + def get_rotation(self): + """ + """ + return self.__rotate + + @graph_is_not_empty + def set_rotation(self, angle): + """ + """ + delta = angle - self.__rotate + self.__rotate = angle + + for node in self.__graph.get_nodes(): + + theta = node.get_coordinate_theta() + node.set_coordinate_theta(theta + delta) + + self.queue_draw() + + def get_translation(self): + """ + """ + return self.__translation + + @graph_is_not_empty + def set_translation(self, translation): + """ + """ + self.__translation = translation + self.queue_draw() + + def is_empty(self): + """ + """ + return self.__graph is None + + def is_in_animation(self): + """ + """ + return self.__animating + + def calc_sorted_nodes(self): + """ + """ + self.__sorted_nodes = list(self.__graph.get_nodes()) + self.__sorted_nodes.sort(key=lambda n: n.get_draw_info('ring')) + + +class NetNode(Node): + """ + Node class for radial network widget + """ + def __init__(self): + """ + """ + self.__draw_info = dict() + """Hash with draw information""" + self.__coordinate = PolarCoordinate() + + super(NetNode, self).__init__() + + def get_host(self): + """ + Set the HostInfo that this node represents + """ + return self.get_data() + + def set_host(self, host): + """ + Set the HostInfo that this node represents + """ + self.set_data(host) + + def get_info(self, info): + """Return various information extracted from the host set with + set_host.""" + host = self.get_data() + if host is not None: + if info == "number_of_open_ports": + return host.get_port_count_by_states(["open"]) + elif info == "vulnerability_score": + num_open_ports = host.get_port_count_by_states(["open"]) + if num_open_ports < 3: + return 0 + elif num_open_ports < 7: + return 1 + else: + return 2 + elif info == "addresses": + addresses = [] + if host.ip is not None: + addresses.append(host.ip) + if host.ipv6 is not None: + addresses.append(host.ipv6) + if host.mac is not None: + addresses.append(host.mac) + return addresses + elif info == "ip": + for addr in (host.ip, host.ipv6, host.mac): + if addr: + return addr.get("addr") + elif info == "hostnames": + hostnames = [] + for hostname in host.hostnames: + copy = {} + copy["name"] = hostname.get("hostname", "") + copy["type"] = hostname.get("hostname_type", "") + hostnames.append(copy) + return hostnames + elif info == "hostname": + return host.get_hostname() + elif info == "uptime": + if host.uptime.get("seconds") or host.uptime.get("lastboot"): + return host.uptime + elif info == "device_type": + osmatch = host.get_best_osmatch() + if osmatch is None: + return None + osclasses = osmatch['osclasses'] + if len(osclasses) == 0: + return None + types = ["router", "wap", "switch", "firewall"] + for type in types: + if type in osclasses[0].get("type", "").lower(): + return type + elif info == "os": + os = {} + + # osmatches + if len(host.osmatches) > 0 and \ + host.osmatches[0]["accuracy"] != "" and \ + host.osmatches[0]["name"] != "": + if os is None: + os = {} + os["matches"] = host.osmatches + os["matches"][0]["db_line"] = 0 # not supported + + os_classes = [] + for osclass in host.osmatches[0]["osclasses"]: + os_class = {} + + os_class["type"] = osclass.get("type", "") + os_class["vendor"] = osclass.get("vendor", "") + os_class["accuracy"] = osclass.get("accuracy", "") + os_class["os_family"] = osclass.get("osfamily", "") + os_class["os_gen"] = osclass.get("osgen", "") + + os_classes.append(os_class) + os["classes"] = os_classes + + # ports_used + if len(host.ports_used) > 0: + if os is None: + os = {} + os_portsused = [] + + for portused in host.ports_used: + os_portused = {} + + os_portused["state"] = portused.get("state", "") + os_portused["protocol"] = portused.get("proto", "") + os_portused["id"] = int(portused.get("portid", "0")) + + os_portsused.append(os_portused) + + os["used_ports"] = os_portsused + + if len(os) > 0: + os["fingerprint"] = "" + return os + elif info == "sequences": + # getting sequences information + sequences = {} + # If all fields are empty, we don't put it into the sequences + # list + if reduce(lambda x, y: x + y, + host.tcpsequence.values(), "") != "": + tcp = {} + if host.tcpsequence.get("index", "") != "": + tcp["index"] = int(host.tcpsequence["index"]) + else: + tcp["index"] = 0 + tcp["class"] = "" # not supported + tcp["values"] = host.tcpsequence.get( + "values", "").split(",") + tcp["difficulty"] = host.tcpsequence.get("difficulty", "") + sequences["tcp"] = tcp + if reduce(lambda x, y: x + y, + host.ipidsequence.values(), "") != "": + ip_id = {} + ip_id["class"] = host.ipidsequence.get("class", "") + ip_id["values"] = host.ipidsequence.get( + "values", "").split(",") + sequences["ip_id"] = ip_id + if reduce(lambda x, y: x + y, + host.tcptssequence.values(), "") != "": + tcp_ts = {} + tcp_ts["class"] = host.tcptssequence.get("class", "") + tcp_ts["values"] = host.tcptssequence.get( + "values", "").split(",") + sequences["tcp_ts"] = tcp_ts + return sequences + elif info == "filtered": + if (len(host.extraports) > 0 and + host.extraports[0]["state"] == "filtered"): + return True + else: + for port in host.ports: + if port["port_state"] == "filtered": + return True + return False + elif info == "ports": + ports = list() + for host_port in host.ports: + port = dict() + state = dict() + service = dict() + + port["id"] = int(host_port.get("portid", "")) + port["protocol"] = host_port.get("protocol", "") + + state["state"] = host_port.get("port_state", "") + state["reason"] = "" # not supported + state["reason_ttl"] = "" # not supported + state["reason_ip"] = "" # not supported + + service["name"] = host_port.get("service_name", "") + service["conf"] = host_port.get("service_conf", "") + service["method"] = host_port.get("service_method", "") + service["version"] = host_port.get("service_version", "") + service["product"] = host_port.get("service_product", "") + service["extrainfo"] = host_port.get( + "service_extrainfo", "") + + port["state"] = state + port["scripts"] = None # not supported + port["service"] = service + + ports.append(port) + return ports + elif info == "extraports": + # extraports + all_extraports = list() + for extraport in host.extraports: + extraports = dict() + extraports["count"] = int(extraport.get("count", "")) + extraports["state"] = extraport.get("state", "") + extraports["reason"] = list() # not supported + extraports["all_reason"] = list() # not supported + + all_extraports.append(extraports) + return all_extraports + elif info == "trace": + # getting traceroute information + if len(host.trace) > 0: + trace = {} + hops = [] + + for host_hop in host.trace.get("hops", []): + hop = {} + hop["ip"] = host_hop.get("ipaddr", "") + hop["ttl"] = int(host_hop.get("ttl", "")) + hop["rtt"] = host_hop.get("rtt", "") + hop["hostname"] = host_hop.get("host", "") + + hops.append(hop) + + trace["hops"] = hops + trace["port"] = host.trace.get("port", "") + trace["protocol"] = host.trace.get("proto", "") + + return trace + else: # host is None + pass + + return None + + def get_coordinate_theta(self): + """ + """ + return self.__coordinate.get_theta() + + def get_coordinate_radius(self): + """ + """ + return self.__coordinate.get_radius() + + def set_coordinate_theta(self, value): + """ + """ + self.__coordinate.set_theta(value) + + def set_coordinate_radius(self, value): + """ + """ + self.__coordinate.set_radius(value) + + def set_polar_coordinate(self, r, t): + """ + Set polar coordinate + @type r: number + @param r: The radius of coordinate + @type t: number + @param t: The angle (theta) of coordinate in radians + """ + self.__coordinate.set_coordinate(r, t) + + def get_polar_coordinate(self): + """ + Get cartesian coordinate + @rtype: tuple + @return: Cartesian coordinates (x, y) + """ + return self.__coordinate.get_coordinate() + + def set_cartesian_coordinate(self, x, y): + """ + Set cartesian coordinate + """ + cartesian = CartesianCoordinate(x, y) + r, t = cartesian.to_polar() + + self.set_polar_coordinate(r, math.degrees(t)) + + def get_cartesian_coordinate(self): + """ + Get cartesian coordinate + @rtype: tuple + @return: Cartesian coordinates (x, y) + """ + return self.__coordinate.to_cartesian() + + def get_draw_info(self, info=None): + """ + Get draw information about node + @type : string + @param : Information name + @rtype: mixed + @return: The requested information + """ + if info is None: + return self.__draw_info + + return self.__draw_info.get(info) + + def set_draw_info(self, info): + """ + Set draw information + @type : dict + @param : Draw information dictionary + """ + for key in info: + self.__draw_info[key] = info[key] + + def deep_search_child(self, node): + """ + """ + for child in self.get_draw_info('children'): + + if child == node: + return True + + elif child.deep_search_child(node): + return True + + return False + + def set_subtree_info(self, info): + """ + """ + for child in self.get_draw_info('children'): + + child.set_draw_info(info) + + if not child.get_draw_info('group'): + child.set_subtree_info(info) + + def calc_needed_space(self): + """ + """ + number_of_children = len(self.get_draw_info('children')) + + sum_angle = 0 + own_angle = 0 + + if number_of_children > 0 and not self.get_draw_info('group'): + + for child in self.get_draw_info('children'): + + child.calc_needed_space() + sum_angle += child.get_draw_info('space_need') + + distance = self.get_coordinate_radius() + size = self.get_draw_info('radius') * 2 + own_angle = geometry.angle_from_object(distance, size) + + self.set_draw_info({'children_need': sum_angle}) + self.set_draw_info({'space_need': max(sum_angle, own_angle)}) diff --git a/zenmap/radialnet/gui/SaveDialog.py b/zenmap/radialnet/gui/SaveDialog.py new file mode 100644 index 0000000..60cfbbe --- /dev/null +++ b/zenmap/radialnet/gui/SaveDialog.py @@ -0,0 +1,169 @@ +# vim: set encoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk + +import os.path +import radialnet.gui.RadialNet as RadialNet +import zenmapGUI.FileChoosers + +from zenmapGUI.higwidgets.higboxes import HIGHBox +from zenmapGUI.higwidgets.higdialogs import HIGAlertDialog + + +TYPES = ((_("By extension"), None, None), + ("PDF", RadialNet.FILE_TYPE_PDF, ".pdf"), + ("PNG", RadialNet.FILE_TYPE_PNG, ".png"), + ("PostScript", RadialNet.FILE_TYPE_PS, ".ps"), + ("SVG", RadialNet.FILE_TYPE_SVG, ".svg")) +# Build a reverse index of extensions to file types, for the "By extension" +# file type. +EXTENSIONS = {} +for type in TYPES: + if type[2] is not None: + EXTENSIONS[type[2]] = type[1] + + +class SaveDialog(Gtk.FileChooserDialog): + def __init__(self): + """ + """ + super(SaveDialog, self).__init__(title=_("Save Topology"), + action=Gtk.FileChooserAction.SAVE, + buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, + Gtk.STOCK_SAVE, Gtk.ResponseType.OK)) + + types_store = Gtk.ListStore.new([str, object, str]) + for type in TYPES: + types_store.append(type) + + self.__combo = Gtk.ComboBox.new_with_model(types_store) + cell = Gtk.CellRendererText() + self.__combo.pack_start(cell, True) + self.__combo.add_attribute(cell, "text", 0) + + self.__combo.connect("changed", self.__combo_changed_cb) + self.__combo.set_active(0) + + self.connect("response", self.__response_cb) + + hbox = HIGHBox() + label = Gtk.Label.new(_("Select File Type:")) + hbox.pack_end(self.__combo, False, True, 0) + hbox.pack_end(label, False, True, 0) + + self.set_extra_widget(hbox) + self.set_do_overwrite_confirmation(True) + + hbox.show_all() + + def __combo_changed_cb(self, widget): + filename = self.get_filename() or "" + dir, basename = os.path.split(filename) + if dir != self.get_current_folder(): + self.set_current_folder(dir) + + # Find the recommended extension. + new_ext = self.__combo.get_model().get_value( + self.__combo.get_active_iter(), 2) + if new_ext is not None: + # Change the filename to use the recommended extension. + root, ext = os.path.splitext(basename) + if len(ext) == 0 and root.startswith("."): + root = "" + self.set_current_name(root + new_ext) + + def __response_cb(self, widget, response_id): + """Intercept the "response" signal to check if someone used the "By + extension" file type with an unknown extension.""" + if response_id == Gtk.ResponseType.OK and self.get_filetype() is None: + ext = self.__get_extension() + if ext == "": + filename = self.get_filename() or "" + dir, basename = os.path.split(filename) + alert = HIGAlertDialog( + message_format=_("No filename extension"), + secondary_text=_("""\ +The filename "%s" does not have an extension, \ +and no specific file type was chosen. +Enter a known extension or select the file type from the list.""" % basename)) + + else: + alert = HIGAlertDialog( + message_format=_("Unknown filename extension"), + secondary_text=_("""\ +There is no file type known for the filename extension "%s". +Enter a known extension or select the file type from the list.\ +""") % self.__get_extension()) + alert.run() + alert.destroy() + # Go back to the dialog. + self.emit_stop_by_name("response") + + def __get_extension(self): + return os.path.splitext(self.get_filename())[1] + + def get_filetype(self): + filetype = self.__combo.get_model().get_value( + self.__combo.get_active_iter(), 1) + if filetype is None: + # Guess based on extension. + return EXTENSIONS.get(self.__get_extension()) + return filetype diff --git a/zenmap/radialnet/gui/Toolbar.py b/zenmap/radialnet/gui/Toolbar.py new file mode 100644 index 0000000..23b7077 --- /dev/null +++ b/zenmap/radialnet/gui/Toolbar.py @@ -0,0 +1,309 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk + +from radialnet.bestwidgets.buttons import BWStockButton, BWToggleStockButton +from radialnet.gui.SaveDialog import SaveDialog +from radialnet.gui.Dialogs import AboutDialog +from radialnet.gui.LegendWindow import LegendWindow +from radialnet.gui.HostsViewer import HostsViewer +from zenmapGUI.higwidgets.higdialogs import HIGAlertDialog + + +SHOW = True +HIDE = False + +REFRESH_RATE = 500 + + +class ToolsMenu(Gtk.Menu): + """ + """ + def __init__(self, radialnet): + """ + """ + Gtk.Menu.__init__(self) + + self.radialnet = radialnet + + self.__create_items() + + def __create_items(self): + """ + """ + self.__hosts = Gtk.ImageMenuItem.new_with_label(_('Hosts viewer')) + self.__hosts.connect("activate", self.__hosts_viewer_callback) + self.__hosts_image = Gtk.Image() + self.__hosts_image.set_from_stock(Gtk.STOCK_INDEX, Gtk.IconSize.MENU) + self.__hosts.set_image(self.__hosts_image) + + self.append(self.__hosts) + + self.__hosts.show_all() + + def __hosts_viewer_callback(self, widget): + """ + """ + window = HostsViewer(self.radialnet.get_scanned_nodes()) + window.show_all() + window.set_keep_above(True) + + def enable_dependents(self): + """ + """ + self.__hosts.set_sensitive(True) + + def disable_dependents(self): + """ + """ + self.__hosts.set_sensitive(False) + + +class Toolbar(Gtk.Box): + """ + """ + def __init__(self, radialnet, window, control, fisheye): + """ + """ + Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL) + #self.set_style(gtk.TOOLBAR_BOTH_HORIZ) + #self.set_tooltips(True) + + self.radialnet = radialnet + + self.__window = window + self.__control_widget = control + self.__fisheye_widget = fisheye + + self.__control_widget.show_all() + self.__control_widget.set_no_show_all(True) + self.__control_widget.hide() + + self.__fisheye_widget.show_all() + self.__fisheye_widget.set_no_show_all(True) + self.__fisheye_widget.hide() + + self.__save_chooser = None + + self.__create_widgets() + + def __create_widgets(self): + """ + """ + # self.__tooltips = gtk.Tooltips() + + #self.__tools_menu = ToolsMenu(self.radialnet) + + #self.__tools_button = gtk.MenuToolButton(gtk.STOCK_PREFERENCES) + #self.__tools_button.set_label(_('Tools')) + #self.__tools_button.set_is_important(True) + #self.__tools_button.set_menu(self.__tools_menu) + #self.__tools_button.connect('clicked', self.__tools_callback) + + self.__save_button = BWStockButton(Gtk.STOCK_SAVE, _("Save Graphic")) + self.__save_button.connect("clicked", self.__save_image_callback) + + self.__hosts_button = BWStockButton(Gtk.STOCK_INDEX, _("Hosts Viewer")) + self.__hosts_button.connect("clicked", self.__hosts_viewer_callback) + + self.__control = BWToggleStockButton( + Gtk.STOCK_PROPERTIES, _("Controls")) + self.__control.connect('clicked', self.__control_callback) + self.__control.set_active(False) + + self.__fisheye = BWToggleStockButton(Gtk.STOCK_ZOOM_FIT, _("Fisheye")) + self.__fisheye.connect('clicked', self.__fisheye_callback) + self.__fisheye.set_active(False) + + self.__legend_button = BWStockButton(Gtk.STOCK_INDEX, _("Legend")) + self.__legend_button.connect('clicked', self.__legend_callback) + + #self.__fullscreen = gtk.ToggleToolButton(gtk.STOCK_FULLSCREEN) + #self.__fullscreen.set_label(_('Fullscreen')) + #self.__fullscreen.set_is_important(True) + #self.__fullscreen.connect('clicked', self.__fullscreen_callback) + #self.__fullscreen.set_tooltip(self.__tooltips, _('Toggle fullscreen')) + + #self.__about = gtk.ToolButton(gtk.STOCK_ABOUT) + #self.__about.set_label(_('About')) + #self.__about.set_is_important(True) + #self.__about.connect('clicked', self.__about_callback) + #self.__about.set_tooltip(self.__tooltips, _('About RadialNet')) + + self.__separator = Gtk.SeparatorToolItem() + self.__expander = Gtk.SeparatorToolItem() + self.__expander.set_expand(True) + self.__expander.set_draw(False) + + #self.insert(self.__open, 0) + #self.insert(self.__separator, 1) + #self.insert(self.__tools_button, 2) + #self.insert(self.__expander, 3) + #self.insert(self.__control, 4) + #self.insert(self.__fisheye, 5) + #self.insert(self.__fullscreen, 6) + #self.insert(self.__about, 7) + + #self.pack_start(self.__tools_button, False) + self.pack_start(self.__hosts_button, False, True, 0) + self.pack_start(self.__fisheye, False, True, 0) + self.pack_start(self.__control, False, True, 0) + self.pack_end(self.__save_button, False, True, 0) + self.pack_end(self.__legend_button, False, True, 0) + + def disable_controls(self): + """ + """ + self.__control.set_sensitive(False) + self.__fisheye.set_sensitive(False) + self.__hosts_button.set_sensitive(False) + self.__legend_button.set_sensitive(False) + #self.__tools_menu.disable_dependents() + + def enable_controls(self): + """ + """ + self.__control.set_sensitive(True) + self.__fisheye.set_sensitive(True) + self.__hosts_button.set_sensitive(True) + self.__legend_button.set_sensitive(True) + #self.__tools_menu.enable_dependents() + + def __tools_callback(self, widget): + """ + """ + self.__tools_menu.popup(None, None, None, 1, 0) + + def __hosts_viewer_callback(self, widget): + """ + """ + window = HostsViewer(self.radialnet.get_scanned_nodes()) + window.show_all() + window.set_keep_above(True) + + def __save_image_callback(self, widget): + """ + """ + if self.__save_chooser is None: + self.__save_chooser = SaveDialog() + + response = self.__save_chooser.run() + + if response == Gtk.ResponseType.OK: + filename = self.__save_chooser.get_filename() + filetype = self.__save_chooser.get_filetype() + + try: + self.radialnet.save_drawing_to_file(filename, filetype) + except Exception as e: + alert = HIGAlertDialog(parent=self.__save_chooser, + type=Gtk.MessageType.ERROR, + message_format=_("Error saving snapshot"), + secondary_text=str(e)) + alert.run() + alert.destroy() + + self.__save_chooser.hide() + + def __control_callback(self, widget=None): + """ + """ + if self.__control.get_active(): + self.__control_widget.show() + + else: + self.__control_widget.hide() + + def __fisheye_callback(self, widget=None): + """ + """ + if not self.radialnet.is_in_animation(): + + if self.__fisheye.get_active(): + + self.__fisheye_widget.active_fisheye() + self.__fisheye_widget.show() + + else: + + self.__fisheye_widget.deactive_fisheye() + self.__fisheye_widget.hide() + + def __legend_callback(self, widget): + """ + """ + self.__legend_window = LegendWindow() + self.__legend_window.show_all() + + def __about_callback(self, widget): + """ + """ + self.__about_dialog = AboutDialog() + self.__about_dialog.show_all() + + def __fullscreen_callback(self, widget=None): + """ + """ + if self.__fullscreen.get_active(): + self.__window.fullscreen() + + else: + self.__window.unfullscreen() diff --git a/zenmap/radialnet/gui/__init__.py b/zenmap/radialnet/gui/__init__.py new file mode 100644 index 0000000..c314dd7 --- /dev/null +++ b/zenmap/radialnet/gui/__init__.py @@ -0,0 +1,56 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ diff --git a/zenmap/radialnet/radialnet.pyw b/zenmap/radialnet/radialnet.pyw new file mode 100755 index 0000000..ff15924 --- /dev/null +++ b/zenmap/radialnet/radialnet.pyw @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +import os +import sys + +from core.ArgvHandle import ArgvHandle +from gui.Application import Application + + +USAGE = """\ +Description: Show RadialNet application from Nmap XML file. It's better if Nmap +XML input file has traceroute information. If you don't know what is this, see +Nmap documentation. You can pass the Nmap xml file by command line or open it +later. + +Usage: radialnet.py [options] + +Options: + + -h, --help Show this help text. + -f <file> Use <file> as Nmap XML input. + +Suggestions or bug reports can be send to ignotus21_at_gmail_dot_com.\ +""" + +# check for psyco +try: + + import psyco + psyco.full() + +except ImportError: + print 'Running without psyco (http://psyco.sourceforge.net/).' + + + +if __name__ == '__main__': + + argvh = ArgvHandle(sys.argv) + + if argvh.has_option('-h') or argvh.has_option('--help'): + + print USAGE + sys.exit(0) + + application = Application() + + if argvh.has_option('-f'): + + file = argvh.get_option('-f') + + if file is None: + + print USAGE + sys.exit(0) + + else: + application.parse_nmap_xml_file(os.path.abspath(file)) + + application.start() diff --git a/zenmap/radialnet/share/sample/nmap_example.xml b/zenmap/radialnet/share/sample/nmap_example.xml new file mode 100644 index 0000000..5e689e8 --- /dev/null +++ b/zenmap/radialnet/share/sample/nmap_example.xml @@ -0,0 +1,480 @@ +<?xml version="1.0" ?> +<?xml-stylesheet href="/opt/nmap/share/nmap/nmap.xsl" type="text/xsl"?> +<!-- Nmap 4.53 scan initiated Sun Jan 27 21:10:02 2008 as: nmap -A -v -oX sample-03.xml freshmeat.net sourceforge.net nmap.org kernel.org openbsd.org netbsd.org google.com gmail.com --> +<nmaprun scanner="nmap" args="nmap -A -v -oX sample-03.xml freshmeat.net sourceforge.net nmap.org kernel.org openbsd.org netbsd.org google.com gmail.com" start="1201479002" startstr="Sun Jan 27 21:10:02 2008" version="4.53" xmloutputversion="1.01"> +<scaninfo type="syn" protocol="tcp" numservices="1714" services="1-1027,1029-1033,1040,1043,1050,1058-1059,1067-1068,1076,1080,1083-1084,1103,1109-1110,1112,1127,1139,1155,1158,1178,1212,1214,1220,1222,1234,1241,1248,1270,1337,1346-1381,1383-1552,1600,1650-1652,1661-1672,1680,1720,1723,1755,1761-1764,1827,1900,1935,1984,1986-2028,2030,2032-2035,2038,2040-2049,2053,2064-2065,2067-2068,2105-2106,2108,2111-2112,2120-2121,2201,2232,2241,2301,2307,2401,2430-2433,2500-2501,2564,2600-2605,2627-2628,2638,2766,2784,2809,2903,2998,3000-3001,3005-3006,3025,3045,3049,3052,3064,3086,3128,3141,3264,3268-3269,3292,3299,3306,3333,3372,3389,3397-3399,3421,3455-3457,3462,3531,3632,3689,3900,3984-3986,3999-4000,4002,4008,4045,4125,4132-4133,4144,4199,4224,4321,4333,4343,4444,4480,4500,4557,4559,4660,4662,4672,4899,4987,4998,5000-5003,5009-5011,5050,5060,5100-5102,5145,5190-5193,5232,5236,5300-5305,5308,5400,5405,5432,5490,5500,5510,5520,5530,5540,5550,5555,5560,5631-5632,5679-5680,5713-5717,5800-5803,5900-5903,5977-5979,5997-6009,6017,6050,6101,6103,6105-6106,6110-6112,6141-6148,6222,6346-6347,6400-6401,6502,6543-6544,6547-6548,6558,6588,6662,6665-6670,6699-6701,6881,6969,7000-7010,7070,7100,7200-7201,7273,7326,7464,7597,7937-7938,8000,8007,8009,8021,8076,8080-8082,8118,8123,8443,8770,8888,8892,9040,9050-9051,9090,9100-9107,9111,9152,9535,9876,9991-9992,9999-10000,10005,10082-10083,11371,12000,12345-12346,13701-13702,13705-13706,13708-13718,13720-13722,13782-13783,14141,15126,15151,16080,16444,16959,17007,17300,18000,18181-18185,18187,19150,20005,22273,22289,22305,22321,22370,26208,27000-27010,27374,27665,31337,31416,32770-32780,32786-32787,38037,38292,43188,44334,44442-44443,47557,49400,50000,50002,54320,61439-61441,65301" /> +<verbose level="1" /> +<debugging level="0" /> +<taskbegin task="Ping Scan" time="1201479013" /> +<taskend task="Ping Scan" time="1201479014" extrainfo="8 total hosts" /> +<taskbegin task="Parallel DNS resolution of 8 hosts." time="1201479014" /> +<taskend task="Parallel DNS resolution of 8 hosts." time="1201479015" /> +<taskbegin task="System CNAME DNS resolution of 4 hosts." time="1201479015" /> +<taskend task="System CNAME DNS resolution of 4 hosts." time="1201479016" /> +<taskbegin task="SYN Stealth Scan" time="1201479016" /> +<taskprogress task="SYN Stealth Scan" time="1201479046" percent="3.22" remaining="903" etc="1201479949" /> +<taskprogress task="SYN Stealth Scan" time="1201479442" percent="56.66" remaining="325" etc="1201479767" /> +<taskprogress task="SYN Stealth Scan" time="1201479770" percent="77.02" remaining="225" etc="1201479995" /> +<taskprogress task="SYN Stealth Scan" time="1201479996" percent="81.95" remaining="215" etc="1201480212" /> +<taskprogress task="SYN Stealth Scan" time="1201480213" percent="86.79" remaining="182" etc="1201480395" /> +<taskprogress task="SYN Stealth Scan" time="1201480260" percent="87.84" remaining="172" etc="1201480433" /> +<taskprogress task="SYN Stealth Scan" time="1201480435" percent="91.65" remaining="129" etc="1201480564" /> +<taskprogress task="SYN Stealth Scan" time="1201480565" percent="94.43" remaining="91" etc="1201480656" /> +<taskprogress task="SYN Stealth Scan" time="1201480658" percent="96.35" remaining="62" etc="1201480720" /> +<taskprogress task="SYN Stealth Scan" time="1201480721" percent="97.76" remaining="39" etc="1201480760" /> +<taskend task="SYN Stealth Scan" time="1201480878" extrainfo="8570 total ports" /> +<taskbegin task="Service scan" time="1201480879" /> +<taskend task="Service scan" time="1201480984" extrainfo="20 services on 5 hosts" /> +<taskbegin task="Traceroute" time="1201481006" /> +<taskend task="Traceroute" time="1201481028" /> +<taskbegin task="Traceroute" time="1201481028" /> +<taskend task="Traceroute" time="1201481059" /> +<taskbegin task="Parallel DNS resolution of 85 hosts." time="1201481059" /> +<taskend task="Parallel DNS resolution of 85 hosts." time="1201481070" /> +<taskbegin task="System CNAME DNS resolution of 8 hosts." time="1201481070" /> +<taskend task="System CNAME DNS resolution of 8 hosts." time="1201481086" /> +<taskbegin task="SCRIPT ENGINE" time="1201481086" /> +<taskend task="SCRIPT ENGINE" time="1201481197" /> +<host><status state="up" reason="reset"/> +<address addr="66.35.250.168" addrtype="ipv4" /> +<hostnames><hostname name="freshmeat.net" type="PTR" /></hostnames> +<ports><extraports state="filtered" count="1712"> +<extrareasons reason="host-prohibiteds" count="1712"/> +</extraports> +<port protocol="tcp" portid="80"><state state="open" reason="syn-ack" reason_ttl="45"/><service name="http" product="Apache httpd" version="1.3.39" extrainfo="(Unix) PHP/4.4.7" method="probed" conf="10" /><script id="robots.txt" output="User-Agent: * /img/ /redir/ " /><script id="HTML title" output="freshmeat.net: Welcome to freshmeat.net" /></port> +<port protocol="tcp" portid="443"><state state="closed" reason="reset" reason_ttl="46"/><service name="https" method="table" conf="3" /></port> +</ports> +<os><portused state="open" proto="tcp" portid="80" /> +<portused state="closed" proto="tcp" portid="443" /> +<osclass type="software router" vendor="MikroTik" osfamily="RouterOS" osgen="2.X" accuracy="94" /> +<osclass type="WAP" vendor="Linksys" osfamily="Linux" osgen="2.4.X" accuracy="94" /> +<osclass type="general purpose" vendor="Linux" osfamily="Linux" osgen="2.4.X" accuracy="94" /> +<osclass type="general purpose" vendor="Linux" osfamily="Linux" osgen="2.6.X" accuracy="94" /> +<osclass type="VoIP phone" vendor="WebVOIZE" osfamily="embedded" accuracy="94" /> +<osclass type="WAP" vendor="D-Link" osfamily="Linux" osgen="2.4.X" accuracy="91" /> +<osclass type="WAP" vendor="Inventel" osfamily="embedded" accuracy="91" /> +<osclass type="broadband router" vendor="USRobotics" osfamily="embedded" accuracy="91" /> +<osclass type="broadband router" vendor="Linux" osfamily="Linux" osgen="2.4.X" accuracy="91" /> +<osclass type="WAP" vendor="Linux" osfamily="Linux" osgen="2.4.X" accuracy="91" /> +<osclass type="media device" vendor="Linux" osfamily="Linux" osgen="2.4.X" accuracy="91" /> +<osclass type="VoIP gateway" vendor="Linux" osfamily="Linux" osgen="2.4.X" accuracy="91" /> +<osclass type="WAP" vendor="Netgear" osfamily="embedded" accuracy="91" /> +<osclass type="switch" vendor="QLogic" osfamily="embedded" accuracy="91" /> +<osclass type="PDA" vendor="Sharp" osfamily="Linux" osgen="2.4.X" accuracy="91" /> +<osclass type="WAP" vendor="FON" osfamily="Linux" osgen="2.6.X" accuracy="91" /> +<osclass type="WAP" vendor="FON" osfamily="Linux" osgen="2.4.X" accuracy="90" /> +<osclass type="WAP" vendor="Belkin" osfamily="embedded" accuracy="90" /> +<osclass type="WAP" vendor="Asus" osfamily="embedded" accuracy="90" /> +<osclass type="WAP" vendor="Netgear" osfamily="Linux" osgen="2.4.X" accuracy="90" /> +<osclass type="printer" vendor="Xerox" osfamily="embedded" accuracy="90" /> +<osclass type="security-misc" vendor="Aladdin" osfamily="Linux" osgen="2.4.X" accuracy="89" /> +<osclass type="VoIP gateway" vendor="Occam" osfamily="embedded" accuracy="89" /> +<osclass type="media device" vendor="Roku" osfamily="embedded" accuracy="89" /> +<osclass type="WAP" vendor="Siemens" osfamily="Linux" accuracy="89" /> +<osclass type="broadband router" vendor="3Com" osfamily="Linux" osgen="2.4.X" accuracy="89" /> +<osclass type="media device" vendor="Dream Multimedia" osfamily="Linux" osgen="2.6.X" accuracy="89" /> +<osclass type="storage-misc" vendor="Iomega" osfamily="Linux" osgen="2.6.X" accuracy="89" /> +<osmatch name="MicroTik RouterOS 2.9.46" accuracy="94" line="14788"/> +<osmatch name="Linksys WRT54GS WAP (Linux kernel)" accuracy="94" line="8292"/> +<osmatch name="Linux 2.4.18 - 2.4.32 (likely embedded)" accuracy="94" line="8499"/> +<osmatch name="Linux 2.4.21 - 2.4.33" accuracy="94" line="8624"/> +<osmatch name="Linux 2.4.27" accuracy="94" line="8675"/> +<osmatch name="Linux 2.4.28 - 2.4.30" accuracy="94" line="8693"/> +<osmatch name="Linux 2.6.5 - 2.6.18" accuracy="94" line="11411"/> +<osmatch name="Linux 2.6.8" accuracy="94" line="11485"/> +<osmatch name="WebVOIZE 120 IP phone" accuracy="94" line="18921"/> +<osmatch name="Linux 2.4.2 (Red Hat 7.1)" accuracy="91" line="8533"/> +<osfingerprint fingerprint="SCAN(V=4.53%D=1/27%OT=80%CT=443%CU=%PV=N%G=N%TM=479D25ED%P=i686-pc-linux-gnu)
SEQ(SP=F2%GCD=1%ISR=E9%TI=Z%TS=1C)
OPS(O1=M5B4ST11NW0%O2=M5B4ST11NW0%O3=M5B4NNT11NW0%O4=M5B4ST11NW0%O5=M5B4ST11NW0%O6=M5B4ST11)
WIN(W1=16A0%W2=16A0%W3=16A0%W4=16A0%W5=16A0%W6=16A0)
ECN(R=Y%DF=Y%TG=40%W=16D0%O=M5B4NNSNW0%CC=N%Q=)
T1(R=Y%DF=Y%TG=40%S=O%A=S+%F=AS%RD=0%Q=)
T2(R=N)
T3(R=Y%DF=Y%TG=40%W=16A0%S=O%A=S+%F=AS%O=M5B4ST11NW0%RD=0%Q=)
T4(R=Y%DF=Y%TG=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)
T5(R=Y%DF=Y%TG=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)
T6(R=Y%DF=Y%TG=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)
T7(R=Y%DF=Y%TG=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)
U1(R=N)
IE(R=N)
" /> +</os> +<uptime seconds="206" lastboot="Sun Jan 27 21:43:11 2008" /> +<tcpsequence index="242" class="unknown class" difficulty="Good luck!" values="457B276,4584FC8,161C122C,161B185F,1605EA95,1614C498" /> +<ipidsequence class="All zeros" values="0,0,0,0,0,0" /> +<tcptssequence class="other" values="3FB03AA9,3FB03C75,45B26360,45B2636A,45B26374,45B2637E" /> +<trace port="80" proto="tcp"> +<hop ttl="1" rtt="1.83" ipaddr="192.168.254.254"/> +<hop ttl="2" rtt="18.95" ipaddr="200.217.89.32"/> +<hop ttl="3" rtt="18.33" ipaddr="200.217.30.250" host="gigabitethernet5-1.80-cto-rn-rotd-02.telemar.net.br"/> +<hop ttl="4" rtt="45.05" ipaddr="200.97.65.250" host="pos15-1-nbv-pe-rotd-03.telemar.net.br"/> +<hop ttl="5" rtt="43.49" ipaddr="200.223.131.13" host="pos6-0-nbv-pe-rotn-01.telemar.net.br"/> +<hop ttl="6" rtt="91.27" ipaddr="200.223.131.205" host="so-0-2-0-0-arc-rj-rotn-01.telemar.net.br"/> +<hop ttl="8" rtt="191.87" ipaddr="200.223.131.110" host="PO0-3.ARC-RJ-ROTN-01.telemar.net.br"/> +<hop ttl="9" rtt="177.30" ipaddr="208.173.90.89" host="bpr2-so-5-2-0.miamimit.savvis.net"/> +<hop ttl="10" rtt="181.50" ipaddr="208.172.97.169" host="cr2-pos-0-3-1-0.miami.savvis.net"/> +<hop ttl="11" rtt="336.43" ipaddr="206.24.210.70" host="cr1-loopback.sfo.savvis.net"/> +<hop ttl="12" rtt="245.32" ipaddr="204.70.200.229" host="er1-te-1-0-1.SanJose3Equinix.savvis.net"/> +<hop ttl="13" rtt="238.47" ipaddr="204.70.200.210" host="hr1-te-2-0-0.santaclarasc4.savvis.net"/> +<hop ttl="14" rtt="322.90" ipaddr="204.70.200.217" host="hr1-te-2-0-0.santaclarasc9.savvis.net"/> +<hop ttl="15" rtt="330.96" ipaddr="204.70.203.146"/> +<hop ttl="16" rtt="342.57" ipaddr="66.35.194.59" host="csr2-ve242.santaclarasc8.savvis.net"/> +<hop ttl="17" rtt="248.22" ipaddr="66.35.210.202"/> +<hop ttl="18" rtt="238.36" ipaddr="66.35.250.168" host="freshmeat.net"/> +</trace> +<times srtt="269788" rttvar="41141" to="434352" /> +</host> +<host><status state="up" reason="reset"/> +<address addr="66.35.250.203" addrtype="ipv4" /> +<hostnames><hostname name="sourceforge.net" type="PTR" /></hostnames> +<ports><extraports state="filtered" count="1711"> +<extrareasons reason="host-prohibiteds" count="1711"/> +</extraports> +<port protocol="tcp" portid="80"><state state="open" reason="syn-ack" reason_ttl="44"/><service name="http" product="lighttpd" version="1.4.18" method="probed" conf="10" /><script id="HTML title" output="Site doesn't have a title." /><script id="robots.txt" output="User-agent: * 
/forum /pm /search /softwaremap /top /tracker /users " /></port> +<port protocol="tcp" portid="443"><state state="open" reason="syn-ack" reason_ttl="44"/><service name="http" product="lighttpd" version="1.4.18" tunnel="ssl" method="probed" conf="10" /><script id="SSLv2" output="server still supports SSLv2
	SSL2_DES_192_EDE3_CBC_WITH_MD5
	SSL2_RC2_CBC_128_CBC_WITH_MD5
	SSL2_RC4_128_WITH_MD5
	SSL2_RC4_64_WITH_MD5
	SSL2_DES_64_CBC_WITH_MD5
	SSL2_RC2_CBC_128_CBC_WITH_MD5
	SSL2_RC4_128_EXPORT40_WITH_MD5
" /><script id="HTML title" output="Site doesn't have a title." /></port> +<port protocol="tcp" portid="563"><state state="closed" reason="reset" reason_ttl="45"/><service name="snews" method="table" conf="3" /></port> +</ports> +<os><portused state="open" proto="tcp" portid="80" /> +<portused state="closed" proto="tcp" portid="563" /> +<osclass type="general purpose" vendor="Linux" osfamily="Linux" osgen="2.6.X" accuracy="94" /> +<osclass type="WAP" vendor="FON" osfamily="Linux" osgen="2.4.X" accuracy="92" /> +<osclass type="WAP" vendor="Siemens" osfamily="Linux" accuracy="90" /> +<osclass type="broadband router" vendor="3Com" osfamily="Linux" osgen="2.4.X" accuracy="90" /> +<osclass type="media device" vendor="Dream Multimedia" osfamily="Linux" osgen="2.6.X" accuracy="90" /> +<osclass type="storage-misc" vendor="Iomega" osfamily="Linux" osgen="2.6.X" accuracy="90" /> +<osclass type="WAP" vendor="FON" osfamily="Linux" osgen="2.6.X" accuracy="90" /> +<osclass type="general purpose" vendor="Linux" osfamily="Linux" osgen="2.4.X" accuracy="90" /> +<osmatch name="Linux 2.6.17 - 2.6.18" accuracy="94" line="9533"/> +<osmatch name="Linux 2.6.17 - 2.6.18 (x86)" accuracy="94" line="9630"/> +<osmatch name="Linux 2.6.9 - 2.6.21" accuracy="94" line="11799"/> +<osmatch name="Linux 2.6.9 - 2.6.20 (Fedora Core 5 or 6)" accuracy="94" line="11777"/> +<osmatch name="FON La Fonera WAP (OpenWrt, Linux 2.4.32)" accuracy="92" line="4356"/> +<osmatch name="Linux 2.6.18.8 (openSUSE 10.2)" accuracy="91" line="10440"/> +<osmatch name="FON La Fonera WAP running OpenWrt w/Linux kernel 2.4.32" accuracy="91" line="4390"/> +<osmatch name="Siemens Gigaset SE515dsl wireless broadband router" accuracy="90" line="17372"/> +<osmatch name="3Com OfficeConnect" accuracy="90" line="250"/> +<osmatch name="Linux 2.6.9 - 2.6.19" accuracy="90" line="4200"/> +<osfingerprint fingerprint="SCAN(V=4.53%D=1/27%OT=80%CT=563%CU=%PV=N%G=N%TM=479D25ED%P=i686-pc-linux-gnu)
SEQ(SP=109%GCD=1%ISR=105%TI=Z%TS=1F)
SEQ(SP=109%GCD=1%ISR=108%TI=Z%II=I%TS=1F)
OPS(O1=M5B4ST11NW3%O2=M5B4ST11NW3%O3=M5B4NNT11NW3%O4=M5B4ST11NW3%O5=M5B4ST11NW3%O6=M5B4ST11)
WIN(W1=16A0%W2=16A0%W3=16A0%W4=16A0%W5=16A0%W6=16A0)
ECN(R=Y%DF=Y%TG=40%W=16D0%O=M5B4NNSNW3%CC=N%Q=)
T1(R=Y%DF=Y%TG=40%S=O%A=S+%F=AS%RD=0%Q=)
T2(R=N)
T3(R=Y%DF=Y%TG=40%W=16A0%S=O%A=S+%F=AS%O=M5B4ST11NW3%RD=0%Q=)
T4(R=Y%DF=Y%TG=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)
T5(R=Y%DF=Y%TG=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)
T6(R=Y%DF=Y%TG=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)
T7(R=Y%DF=Y%TG=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)
U1(R=N)
IE(R=Y%DFI=N%TG=40%TOSI=S%CD=S%SI=S%DLI=S)
" /> +</os> +<uptime seconds="201" lastboot="Sun Jan 27 21:43:16 2008" /> +<tcpsequence index="265" class="unknown class" difficulty="Good luck!" values="E7AA462B,41E21423,41900EE4,B0406748,AF655A96" /> +<ipidsequence class="All zeros" values="0,0,0,0,0" /> +<tcptssequence class="other" values="45702AB,E5E6ADFA,E5E6AE64,FA2DC6F6,FA2DC756" /> +<trace port="80" proto="tcp"> +<hop ttl="1" rtt="--" ipaddr="192.168.254.254"/> +<hop ttl="2" rtt="--" ipaddr="200.217.89.32"/> +<hop ttl="3" rtt="--" ipaddr="200.217.30.250" host="gigabitethernet5-1.80-cto-rn-rotd-02.telemar.net.br"/> +<hop ttl="4" rtt="--" ipaddr="200.97.65.250" host="pos15-1-nbv-pe-rotd-03.telemar.net.br"/> +<hop ttl="5" rtt="44.53" ipaddr="200.223.131.13" host="pos6-0-nbv-pe-rotn-01.telemar.net.br"/> +<hop ttl="6" rtt="96.74" ipaddr="200.223.131.2" host="pos2-0-bvg-pe-rotn-01.telemar.net.br"/> +<hop ttl="7" rtt="243.94" ipaddr="200.223.131.18" host="pos9-0-asgs-ba-rotn-01.telemar.net.br"/> +<hop ttl="8" rtt="92.72" ipaddr="200.223.131.74" host="so-0-2-2-0-bot-rj-rotn-01.telemar.net.br"/> +<hop ttl="9" rtt="189.57" ipaddr="200.223.131.110" host="PO0-3.ARC-RJ-ROTN-01.telemar.net.br"/> +<hop ttl="10" rtt="187.09" ipaddr="208.173.90.89" host="bpr2-so-5-2-0.miamimit.savvis.net"/> +<hop ttl="11" rtt="185.44" ipaddr="208.172.97.169" host="cr2-pos-0-3-1-0.miami.savvis.net"/> +<hop ttl="12" rtt="246.55" ipaddr="206.24.210.70" host="cr1-loopback.sfo.savvis.net"/> +<hop ttl="13" rtt="246.08" ipaddr="204.70.200.229" host="er1-te-1-0-1.SanJose3Equinix.savvis.net"/> +<hop ttl="14" rtt="242.86" ipaddr="204.70.200.210" host="hr1-te-2-0-0.santaclarasc4.savvis.net"/> +<hop ttl="15" rtt="333.68" ipaddr="204.70.200.217" host="hr1-te-2-0-0.santaclarasc9.savvis.net"/> +<hop ttl="16" rtt="245.30" ipaddr="204.70.203.146"/> +<hop ttl="17" rtt="258.32" ipaddr="66.35.194.58" host="csr1-ve242.santaclarasc8.savvis.net"/> +<hop ttl="18" rtt="249.12" ipaddr="66.35.212.174"/> +<hop ttl="19" rtt="251.98" ipaddr="66.35.250.203" host="sourceforge.net"/> +</trace> +<times srtt="285380" rttvar="52198" to="494172" /> +</host> +<host><status state="up" reason="reset"/> +<address addr="64.13.134.48" addrtype="ipv4" /> +<hostnames /> +<ports><extraports state="filtered" count="1708"> +<extrareasons reason="no-responses" count="1708"/> +</extraports> +<port protocol="tcp" portid="22"><state state="open" reason="syn-ack" reason_ttl="48"/><service name="ssh" product="OpenSSH" version="4.3" extrainfo="protocol 2.0" method="probed" conf="10" /></port> +<port protocol="tcp" portid="25"><state state="closed" reason="reset" reason_ttl="47"/><service name="smtp" method="table" conf="3" /></port> +<port protocol="tcp" portid="53"><state state="open" reason="syn-ack" reason_ttl="47"/><service name="domain" method="probed" conf="10" /></port> +<port protocol="tcp" portid="70"><state state="closed" reason="reset" reason_ttl="47"/><service name="gopher" method="table" conf="3" /></port> +<port protocol="tcp" portid="80"><state state="open" reason="syn-ack" reason_ttl="47"/><service name="http" product="Apache httpd" version="2.2.2" extrainfo="(Fedora)" method="probed" conf="10" /><script id="HTML title" output="Nmap - Free Security Scanner For Network Exploration & Securit..." /></port> +<port protocol="tcp" portid="113"><state state="closed" reason="reset" reason_ttl="47"/><service name="auth" method="table" conf="3" /></port> +</ports> +<os><portused state="open" proto="tcp" portid="22" /> +<portused state="closed" proto="tcp" portid="25" /> +<osclass type="general purpose" vendor="Linux" osfamily="Linux" osgen="2.6.X" accuracy="100" /> +<osmatch name="Linux 2.6.17 - 2.6.21" accuracy="100" line="9847" /> +<osfingerprint fingerprint="SCAN(V=4.53%D=1/27%OT=22%CT=25%CU=%PV=N%G=N%TM=479D25ED%P=i686-pc-linux-gnu)
SEQ(SP=C4%GCD=1%ISR=D4%TI=Z%II=I%TS=A)
OPS(O1=M5B4ST11NW7%O2=M5B4ST11NW7%O3=M5B4NNT11NW7%O4=M5B4ST11NW7%O5=M5B4ST11NW7%O6=M5B4ST11)
WIN(W1=16A0%W2=16A0%W3=16A0%W4=16A0%W5=16A0%W6=16A0)
ECN(R=Y%DF=Y%TG=40%W=16D0%O=M5B4NNSNW7%CC=N%Q=)
T1(R=Y%DF=Y%TG=40%S=O%A=S+%F=AS%RD=0%Q=)
T2(R=N)
T3(R=Y%DF=Y%TG=40%W=16A0%S=O%A=S+%F=AS%O=M5B4ST11NW7%RD=0%Q=)
T4(R=Y%DF=Y%TG=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)
T5(R=Y%DF=Y%TG=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)
T6(R=Y%DF=Y%TG=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)
T7(R=Y%DF=Y%TG=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)
U1(R=N)
IE(R=Y%DFI=N%TG=40%TOSI=S%CD=S%SI=S%DLI=S)
" /> +</os> +<uptime seconds="3678886" lastboot="Sun Dec 16 07:51:51 2007" /> +<tcpsequence index="196" class="unknown class" difficulty="Good luck!" values="3B4828E4,3C05079E,3B93665A,3C0C2FD5,3B4F7938,3BD91399" /> +<ipidsequence class="All zeros" values="0,0,0,0,0,0" /> +<tcptssequence class="1000HZ" values="DB441BF8,DB441C5D,DB441CC1,DB441D24,DB441D88,DB441DED" /> +<trace port="22" proto="tcp"> +<hop ttl="1" rtt="--" ipaddr="192.168.254.254"/> +<hop ttl="2" rtt="--" ipaddr="200.217.89.32"/> +<hop ttl="3" rtt="--" ipaddr="200.217.30.250" host="gigabitethernet5-1.80-cto-rn-rotd-02.telemar.net.br"/> +<hop ttl="4" rtt="--" ipaddr="200.97.65.250" host="pos15-1-nbv-pe-rotd-03.telemar.net.br"/> +<hop ttl="5" rtt="2887.23" ipaddr="200.223.131.13" host="pos6-0-nbv-pe-rotn-01.telemar.net.br"/> +<hop ttl="7" rtt="109.87" ipaddr="200.223.131.134" host="so-0-2-1-0-bot-rj-rotn-01.telemar.net.br"/> +<hop ttl="8" rtt="185.40" ipaddr="200.187.128.66"/> +<hop ttl="10" rtt="186.95" ipaddr="64.125.13.69" host="ge-6-1-0.mpr1.iad10.us.above.net"/> +<hop ttl="11" rtt="191.85" ipaddr="64.125.30.118" host="so-4-0-0.mpr1.iad2.us.above.net"/> +<hop ttl="12" rtt="191.88" ipaddr="64.125.27.74" host="so-6-0-0.mpr1.iad5.us.above.net"/> +<hop ttl="13" rtt="212.11" ipaddr="64.125.29.229" host="so-4-0-0.mpr1.iad1.us.above.net"/> +<hop ttl="14" rtt="192.05" ipaddr="64.125.28.62" host="so-0-2-0.mpr1.lga5.us.above.net"/> +<hop ttl="15" rtt="275.83" ipaddr="64.125.26.229" host="so-2-1-0.mpr1.sjc2.above.net"/> +<hop ttl="16" rtt="268.86" ipaddr="64.125.28.142" host="so-4-2-0.mpr3.pao1.us.above.net"/> +<hop ttl="17" rtt="299.43" ipaddr="208.185.168.173" host="metro0.sv.svcolo.com"/> +<hop ttl="18" rtt="352.22" ipaddr="64.13.134.48"/> +</trace> +<times srtt="373460" rttvar="156723" to="1000352" /> +</host> +<host><status state="up" reason="reset"/> +<address addr="204.152.191.37" addrtype="ipv4" /> +<hostnames><hostname name="pub2.kernel.org" type="PTR" /></hostnames> +<ports><extraports state="closed" count="1704"> +<extrareasons reason="resets" count="1704"/> +</extraports> +<port protocol="tcp" portid="21"><state state="open" reason="syn-ack" reason_ttl="50"/><service name="ftp" product="vsftpd or WU-FTPD" hostname="Welcome" method="probed" conf="10" /><script id="Anonymous FTP" output="FTP: Anonymous login allowed" /></port> +<port protocol="tcp" portid="22"><state state="open" reason="syn-ack" reason_ttl="50"/><service name="ssh" product="OpenSSH" version="4.3" extrainfo="protocol 2.0" method="probed" conf="10" /></port> +<port protocol="tcp" portid="79"><state state="open" reason="syn-ack" reason_ttl="50"/><service name="finger" servicefp="SF-Port79-TCP:V=4.53%I=7%D=1/27%Time=479D24B2%P=i686-pc-linux-gnu%r(NULL,1
SF:A3,"The\x20latest\x20stable\x20version\x20of\x20the\x20Linux\x20kernel\
SF:x20is:\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x202\.6\.24\nThe\x20late
SF:st\x20snapshot\x20for\x20the\x20stable\x20Linux\x20kernel\x20tree\x20is
SF::\x20\x20\x20\x202\.6\.24-git3\nThe\x20latest\x202\.4\x20version\x20of\
SF:x20the\x20Linux\x20kernel\x20is:\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2
SF:0\x20\x20\x20\x202\.4\.36\nThe\x20latest\x202\.2\x20version\x20of\x20th
SF:e\x20Linux\x20kernel\x20is:\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
SF:\x20\x20\x202\.2\.26\nThe\x20latest\x20prepatch\x20for\x20the\x202\.2\x
SF:20Linux\x20kernel\x20tree\x20is:\x20\x20\x20\x20\x20\x20\x202\.2\.27-rc
SF:2\nThe\x20latest\x20-mm\x20patch\x20to\x20the\x20stable\x20Linux\x20ker
SF:nels\x20is:\x20\x20\x20\x20\x20\x20\x20\x202\.6\.24-rc8-mm1\n")%r(Gener
SF:icLines,1A3,"The\x20latest\x20stable\x20version\x20of\x20the\x20Linux\x
SF:20kernel\x20is:\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x202\.6\.24\nTh
SF:e\x20latest\x20snapshot\x20for\x20the\x20stable\x20Linux\x20kernel\x20t
SF:ree\x20is:\x20\x20\x20\x202\.6\.24-git3\nThe\x20latest\x202\.4\x20versi
SF:on\x20of\x20the\x20Linux\x20kernel\x20is:\x20\x20\x20\x20\x20\x20\x20\x
SF:20\x20\x20\x20\x20\x20\x202\.4\.36\nThe\x20latest\x202\.2\x20version\x2
SF:0of\x20the\x20Linux\x20kernel\x20is:\x20\x20\x20\x20\x20\x20\x20\x20\x2
SF:0\x20\x20\x20\x20\x202\.2\.26\nThe\x20latest\x20prepatch\x20for\x20the\
SF:x202\.2\x20Linux\x20kernel\x20tree\x20is:\x20\x20\x20\x20\x20\x20\x202\
SF:.2\.27-rc2\nThe\x20latest\x20-mm\x20patch\x20to\x20the\x20stable\x20Lin
SF:ux\x20kernels\x20is:\x20\x20\x20\x20\x20\x20\x20\x202\.6\.24-rc8-mm1\n"
SF:)%r(GetRequest,1A3,"The\x20latest\x20stable\x20version\x20of\x20the\x20
SF:Linux\x20kernel\x20is:\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x202\.6\
SF:.24\nThe\x20latest\x20snapshot\x" method="table" conf="3" /></port> +<port protocol="tcp" portid="80"><state state="open" reason="syn-ack" reason_ttl="50"/><service name="http" product="Apache httpd" version="2.2.2" extrainfo="(Fedora)" method="probed" conf="10" /><script id="robots.txt" output="
/cgi-bin/ /pub/mirrors/ /pub/scm/ 
/mirrors/process-registration.cgi /lsb/ /linuxeda/ /os.org/ /debian/ 
/debian-cd/ /lanana/ /li18nux/ /freestandards/ 
/filehub/ /diff/ /git/ /hg/ " /><script id="HTML title" output="The Linux Kernel Archives" /></port> +<port protocol="tcp" portid="199"><state state="open" reason="syn-ack" reason_ttl="50"/><service name="smux" product="Linux SNMP multiplexer" ostype="Linux" method="probed" conf="10" /></port> +<port protocol="tcp" portid="443"><state state="open" reason="syn-ack" reason_ttl="50"/><service name="https" tunnel="ssl" method="table" conf="3" /><script id="HTML title" output="The Linux Kernel Archives" /></port> +<port protocol="tcp" portid="873"><state state="open" reason="syn-ack" reason_ttl="53"/><service name="rsync" extrainfo="protocol version 29" method="probed" conf="10" /></port> +<port protocol="tcp" portid="1720"><state state="filtered" reason="no-response" reason_ttl="0"/><service name="H.323/Q.931" method="table" conf="3" /></port> +<port protocol="tcp" portid="5978"><state state="open" reason="syn-ack" reason_ttl="50"/><service name="ncd-diag-tcp" method="table" conf="3" /></port> +<port protocol="tcp" portid="7000"><state state="open" reason="syn-ack" reason_ttl="53"/><service name="afs3-fileserver" method="table" conf="3" /></port> +</ports> +<os><portused state="open" proto="tcp" portid="21" /> +<portused state="closed" proto="tcp" portid="1" /> +<portused state="closed" proto="udp" portid="34527" /> +<osclass type="general purpose" vendor="Linux" osfamily="Linux" osgen="2.6.X" accuracy="91" /> +<osclass type="security-misc" vendor="Aladdin" osfamily="Linux" osgen="2.4.X" accuracy="88" /> +<osclass type="general purpose" vendor="Linux" osfamily="Linux" osgen="2.4.X" accuracy="87" /> +<osclass type="switch" vendor="QLogic" osfamily="embedded" accuracy="87" /> +<osclass type="PDA" vendor="Sharp" osfamily="Linux" osgen="2.4.X" accuracy="87" /> +<osclass type="VoIP gateway" vendor="Tandberg" osfamily="Linux" osgen="2.6.X" accuracy="87" /> +<osclass type="WAP" vendor="Siemens" osfamily="Linux" accuracy="87" /> +<osclass type="server appliance" vendor="Toshiba" osfamily="Linux" osgen="2.4.X" accuracy="87" /> +<osclass type="VoIP gateway" vendor="Occam" osfamily="embedded" accuracy="86" /> +<osclass type="WAP" vendor="FON" osfamily="Linux" osgen="2.4.X" accuracy="86" /> +<osclass type="media device" vendor="Dream Multimedia" osfamily="Linux" osgen="2.6.X" accuracy="85" /> +<osclass type="storage-misc" vendor="Iomega" osfamily="Linux" osgen="2.6.X" accuracy="85" /> +<osclass type="WAP" vendor="Inventel" osfamily="embedded" accuracy="85" /> +<osclass type="broadband router" vendor="USRobotics" osfamily="embedded" accuracy="85" /> +<osclass type="broadband router" vendor="Linux" osfamily="Linux" osgen="2.4.X" accuracy="85" /> +<osclass type="WAP" vendor="Linux" osfamily="Linux" osgen="2.4.X" accuracy="85" /> +<osclass type="media device" vendor="Linux" osfamily="Linux" osgen="2.4.X" accuracy="85" /> +<osclass type="VoIP gateway" vendor="Linux" osfamily="Linux" osgen="2.4.X" accuracy="85" /> +<osmatch name="Linux 2.6.5 - 2.6.9" accuracy="91" line="11429"/> +<osmatch name="Linux 2.6.17 - 2.6.18" accuracy="91" line="9552"/> +<osmatch name="Linux 2.6.22" accuracy="89" line="11205"/> +<osmatch name="Linux 2.6.15.4" accuracy="89" line="9337"/> +<osmatch name="Linux 2.6.9-022stab078.19-enterprise (CentOS 4.2 x86)" accuracy="89" line="11816"/> +<osmatch name="Linux 2.6.17 - 2.6.18 (x86_64, SMP)" accuracy="89" line="9650"/> +<osmatch name="Linux 2.6.17 - 2.6.21" accuracy="89" line="9847"/> +<osmatch name="Linux 2.6.18 (Gentoo, x86)" accuracy="89" line="10263"/> +<osmatch name="Linux 2.6.5-7.283-smp (SuSE Enterprise Server 9, x86)" accuracy="88" line="11465"/> +<osmatch name="Aladdin eSafe security gateway (runs Linux 2.4.21)" accuracy="88" line="463"/> +<osfingerprint fingerprint="SCAN(V=4.53%D=1/27%OT=21%CT=1%CU=34527%PV=N%DS=13%G=N%TM=479D25ED%P=i686-pc-linux-gnu)
SEQ(SP=CB%GCD=1%ISR=CF%TI=Z%TS=E)
SEQ(SP=CB%GCD=1%ISR=CF%TI=Z%II=I%TS=D)
OPS(O1=M5B4ST11NW7%O2=M5B4ST11NW7%O3=M5B4NNT11NW7%O4=M5B4ST11NW7%O5=M5B4ST11NW7%O6=M5B4ST11)
WIN(W1=16A0%W2=16A0%W3=16A0%W4=16A0%W5=16A0%W6=16A0)
ECN(R=Y%DF=Y%T=3F%W=16D0%O=M5B4NNSNW7%CC=N%Q=)
T1(R=Y%DF=Y%T=3F%S=O%A=S+%F=AS%RD=0%Q=)
T2(R=N)
T3(R=Y%DF=Y%T=3F%W=16A0%S=O%A=S+%F=AS%O=M5B4ST11NW7%RD=0%Q=)
T4(R=Y%DF=Y%T=3F%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)
T5(R=Y%DF=Y%T=3F%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)
T6(R=Y%DF=Y%T=3F%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)
T7(R=Y%DF=Y%T=3F%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)
U1(R=Y%DF=N%T=3F%TOS=0%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=ABF4%RUL=G%RUD=G)
IE(R=Y%DFI=N%T=3F%TOSI=Z%CD=S%SI=S%DLI=S)
IE(R=Y%DFI=N%T=42%TOSI=Z%CD=S%SI=S%DLI=S)
" /> +</os> +<uptime seconds="404814" lastboot="Wed Jan 23 05:19:43 2008" /> +<distance value="13" /> +<tcpsequence index="203" class="unknown class" difficulty="Good luck!" values="51411AEE,509EEED0,508D446B,50BABE19,5110A098,506A461E" /> +<ipidsequence class="All zeros" values="0,0,0,0,0,0" /> +<tcptssequence class="other" values="A4550333,A455026B,A454F6B8,A454F71A,A454F77F,A454F7DB" /> +<trace port="21" proto="tcp"> +<hop ttl="1" rtt="2.66" ipaddr="192.168.254.254"/> +<hop ttl="2" rtt="27.86" ipaddr="200.217.89.32"/> +<hop ttl="3" rtt="46.94" ipaddr="200.217.30.210" host="gigabitethernet6-1.90-cto-rn-rotd-02.telemar.net.br"/> +<hop ttl="4" rtt="53.15" ipaddr="200.97.65.250" host="pos15-1-nbv-pe-rotd-03.telemar.net.br"/> +<hop ttl="5" rtt="47.43" ipaddr="200.223.131.13" host="pos6-0-nbv-pe-rotn-01.telemar.net.br"/> +<hop ttl="8" rtt="181.54" ipaddr="200.223.131.246"/> +<hop ttl="9" rtt="183.95" ipaddr="209.58.18.1" host="if-0-11.ihar1.N60-NewYork.teleglobe.net"/> +<hop ttl="10" rtt="267.48" ipaddr="216.6.87.17" host="if-12-0.mcore4.NQT-NewYork.teleglobe.net"/> +<hop ttl="11" rtt="347.36" ipaddr="216.6.86.13" host="if-4-0.mcore4.PDI-PaloAlto.teleglobe.net"/> +<hop ttl="12" rtt="345.61" ipaddr="216.6.86.2" host="if-7-0.core3.PDI-PaloAlto.teleglobe.net"/> +<hop ttl="13" rtt="337.96" ipaddr="207.45.196.66" host="ix-4-6.core3.PDI-PaloAlto.Teleglobe.net"/> +<hop ttl="14" rtt="251.55" ipaddr="204.152.191.37" host="pub2.kernel.org"/> +</trace> +<times srtt="302981" rttvar="47378" to="492493" /> +</host> +<host><status state="up" reason="echo-reply"/> +<address addr="199.185.137.3" addrtype="ipv4" /> +<hostnames><hostname name="cvs.openbsd.org" type="PTR" /></hostnames> +<ports><extraports state="filtered" count="1019"> +<extrareasons reason="host-unreaches" count="1013"/> +<extrareasons reason="no-responses" count="6"/> +</extraports> +<extraports state="closed" count="690"> +<extrareasons reason="resets" count="690"/> +</extraports> +<port protocol="tcp" portid="21"><state state="open" reason="syn-ack" reason_ttl="48"/><service name="ftp" product="bsd-ftpd" hostname="cvs.openbsd.org" ostype="Linux" method="probed" conf="10" /></port> +<port protocol="tcp" portid="25"><state state="open" reason="syn-ack" reason_ttl="46"/><service name="smtp" product="OpenBSD spamd" method="probed" conf="10" /><script id="SMTP" output="EHLO with errors or timeout. Enable --script-trace to see what is happening." /></port> +<port protocol="tcp" portid="53"><state state="open" reason="syn-ack" reason_ttl="45"/><service name="domain" product="ISC BIND" version="9.X" method="probed" conf="10" /><script id="zone-transfer" output=" 
openbsd.org. SOA zeus.theos.com. root.theos.com. 
openbsd.org. NS ns.appli.se. 
openbsd.org. NS ns	sigmasoft.com. 
openbsd.org. NS cvs.openbsd.org. 
openbsd.org. NS citi.umich.edu. 
openbsd.org. NS zeus.theos.com. 
openbsd.org. A 199.185.137.3 
openbsd.org. MX shear.ucar.edu. 
openbsd.org. MX cvs.openbsd.org. 
alpha.openbsd.org. A 199.185.137.77 
amd64.openbsd.org. A 199.185.137.80 
anoncvs.openbsd.org. CNAME 
ftp.ar.openbsd.org. CNAME 
ftp1.ar.openbsd.org. CNAME 
www.ar.openbsd.org. CNAME 
armish.openbsd.org. A 199.185.137.155 
ftp.as.openbsd.org. CNAME 
ftp1.as.openbsd.org. CNAME 
ftp2.as.openbsd.org. CNAME 
ftp3.as.openbsd.org. CNAME 
ftp4.as.openbsd.org. CNAME 
anoncvs2.at.openbsd.org. A 128.130.59.60 
www.at.openbsd.org. CNAME 
ftp.au.openbsd.org. CNAME 
ftp1.au.openbsd.org. CNAME 
ftp2.au.openbsd.org. CNAME 
ftp3.au.openbsd.org. CNAME 
www.au.openbsd.org. CNAME 
cvsup.bg.openbsd.org. A 217.10.246.146 
ftp.bg.openbsd.org. A 217.10.246.146 
ftp1.bg.openbsd.org. A 217.10.246.146 
c.openbsd.org. CNAME 
anoncvs.ca.openbsd.org. CNAME 
anoncvs1.ca.openbsd.org. CNAME 
ctm.ca.openbsd.org. CNAME 
cvsup.ca.openbsd.org. A 206.51.28.249 
ftp.ca.openbsd.org. CNAME 
ftp1.ca.openbsd.org. CNAME 
www.ca.openbsd.org. A 129.128.5.191 
cats.openbsd.org. A 199.185.137.33 
ctm.openbsd.org. CNAME 
cvs.openbsd.org. A 199.185.137.3 
cvsup.openbsd.org. CNAME 
de.openbsd.org. NS a.ns.bsws.de. 
de.openbsd.org. NS a.ns	pestilenz.org. 
de.openbsd.org. NS b.ns.bsws.de. 
de.openbsd.org. NS c.ns.bsws.de. 
ftp.eu.openbsd.org. CNAME 
ftp1.eu.openbsd.org. CNAME 
ftp2.eu.openbsd.org. CNAME 
ftp3.eu.openbsd.org. CNAME 
ftp4.eu.openbsd.org. CNAME 
ftp5.eu.openbsd.org. CNAME 
ftp6.eu.openbsd.org. CNAME 
ftp8.eu.openbsd.org. CNAME 
ftp9.eu.openbsd.org. A 193.120.14.244 
cvsup.fr.openbsd.org. CNAME 
ftp.fr.openbsd.org. CNAME 
ftp1.fr.openbsd.org. CNAME 
ftp2.fr.openbsd.org. CNAME 
ftp3.fr.openbsd.org. CNAME 
ftp.openbsd.org. CNAME 
gw.openbsd.org. A 199.185.230.1 
hp3...openbsd.org. A 199.185.137.74 
hppa.openbsd.org. A 199.185.137.79 
https.openbsd.org. A 68.148.128.241 
cvsup.hu.openbsd.org. CNAME 
i386.openbsd.org. A 199.185.137.8 
cvsup.id.openbsd.org. CNAME 
ftp.ie.openbsd.org. A 193.120.14.244 
ftp19.ie.openbsd.org. A 193.120.14.244 
www.ie.openbsd.org. A 193.120.14.244 
anoncvs.jp.openbsd.org. CNAME 
anoncvs1.jp.openbsd.org. CNAME 
cvsup.jp.openbsd.org. CNAME 
ftp.jp.openbsd.org. CNAME 
ftp1.jp.openbsd.org. CNAME 
ftp2.jp.openbsd.org. CNAME 
www.jp.openbsd.org. CNAME 
cvsup.kr.openbsd.org. CNAME 
ftp.kr.openbsd.org. CNAME 
ftp1.kr.openbsd.org. CNAME 
landisk.openbsd.org. A 199.185.137.81 
landiskx.openbsd.org. A 199.185.137.157 
list.openbsd.org. CNAME 
lists.openbsd.org. CNAME 
localhost.openbsd.org. A 127.0.0.1 
loghost.openbsd.org. CNAME 
macppc.openbsd.org. A 199.185.137.87 
mail.openbsd.org. CNAME 
music.openbsd.org. A 199.185.137.230 
mvme68k.openbsd.org. A 199.185.137.42 
mvme88k.openbsd.org. A 199.185.137.88 
n.openbsd.org. A 199.185.136.200 
n.openbsd.org. MX cvs.openbsd.org. 
anoncvs.nl.openbsd.org. CNAME 
anoncvs1.nl.openbsd.org. CNAME 
anoncvs.no.openbsd.org. CNAME 
anoncvs1.no.openbsd.org. CNAME 
cvsup.no.openbsd.org. CNAME 
anoncvs.nyc.openbsd.org. CNAME 
ftp.nyc.openbsd.org. CNAME 
ops.openbsd.org. A 199.185.137.129 
pf.openbsd.org. A 199.185.136.128 
pf.openbsd.org. A 199.185.137.128 
pf.openbsd.org. A 199.185.231.128 
pf.openbsd.org. A 207.153.1.26 
anoncvs.pl.openbsd.org. CNAME 
anoncvs1.pl.openbsd.org. CNAME 
pmax.openbsd.org. A 199.185.137.52 
ports.openbsd.org. CNAME 
alpha.ports.openbsd.org. A 199.185.231.77 
amd64.ports.openbsd.org. A 199.185.231.80 
armish.ports.openbsd.org. A 199.185.231.155 
cvs.ports.openbsd.org. CNAME 
hppa.ports.openbsd.org. A 199.185.231.78 
i386.ports.openbsd.org. A 199.185.231.6 
landisk.ports.openbsd.org. A 199.185.231.81 
m68k.ports.openbsd.org. A 199.185.231.7 
macppc.ports.openbsd.org. A 199.185.231.8 
serial.ports.openbsd.org. A 199.185.231.111 
sgi.ports.openbsd.org. A 199.185.231.99 
sparc.ports.openbsd.org. A 199.185.231.5 
sparc-..ports.openbsd.org. CNAME 
sparc-1.ports.openbsd.org. A 199.185.231.20 
sparc-2.ports.openbsd.org. A 199.185.231.21 
sparc-3.ports.openbsd.org. A 199.185.231.22 
sparc64.ports.openbsd.org. A 199.185.231.94 
sparc64-..ports.openbsd.org. CNAME 
sparc64-1.ports.openbsd.org. A 199.185.231.95 
sparc64-2.ports.openbsd.org. A 199.185.231.96 
sparc64-3.ports.openbsd.org. A 199.185.231.97 
sparc64-4.ports.openbsd.org. A 199.185.231.98 
vax.ports.openbsd.org. A 199.185.231.79 
zaurus.ports.openbsd.org. A 199.185.231.50 
cvsup.pt.openbsd.org. CNAME 
ftp.ro.openbsd.org. CNAME 
ftp1.ro.openbsd.org. CNAME 
anoncvs.se.openbsd.org. CNAME 
anoncvs1.se.openbsd.org. CNAME 
ctm.se.openbsd.org. CNAME 
ftp.se.openbsd.org. CNAME 
ftp1.se.openbsd.org. CNAME 
serial.openbsd.org. A 199.185.137.111 
sgi.openbsd.org. A 199.185.137.99 
sparc.openbsd.org. A 199.185.137.92 
sparc64.openbsd.org. A 199.185.137.94 
test.openbsd.org. A 199.185.137.17 
test2.openbsd.org. A 199.185.137.18 
test3.openbsd.org. A 199.185.137.19 
test4.openbsd.org. A 199.185.137.20 
ftp.th.openbsd.org. CNAME 
ftp1.th.openbsd.org. CNAME 
www.tr.openbsd.org. CNAME 
anoncvs.tw.openbsd.org. CNAME 
anoncvs1.tw.openbsd.org. CNAME 
cvsup.tw.openbsd.org. A 140.113.17.208 
ftp.tw.openbsd.org. CNAME 
ftp1.tw.openbsd.org. CNAME 
www.tw.openbsd.org. CNAME 
u.openbsd.org. A 199.185.136.4 
u.openbsd.org. MX cvs.openbsd.org. 
cvsup.uk.openbsd.org. A 194.242.139.171 
anoncvs.usa.openbsd.org. CNAME 
anoncvs1.usa.openbsd.org. CNAME 
anoncvs2.usa.openbsd.org. CNAME 
anoncvs3.usa.openbsd.org. CNAME 
anoncvs4.usa.openbsd.org. CNAME 
anoncvs5.usa.openbsd.org. CNAME 
anoncvs6.usa.openbsd.org. CNAME 
cvsup.usa.openbsd.org. A 128.46.156.46 
ftp.usa.openbsd.org. CNAME 
ftp1.usa.openbsd.org. CNAME 
ftp2.usa.openbsd.org. CNAME 
ftp3.usa.openbsd.org. CNAME 
ftp5.usa.openbsd.org. CNAME 
ftp6.usa.openbsd.org. CNAME 
www.usa.openbsd.org. A 198.175.14.3 
v.openbsd.org. A 199.185.136.2 
v.openbsd.org. MX cvs.openbsd.org. 
vax.openbsd.org. A 199.185.137.78 
w.openbsd.org. A 199.185.136.3 
w.openbsd.org. MX cvs.openbsd.org. 
www.openbsd.org. A 129.128.5.191 
x.openbsd.org. A 199.185.136.5 
x.openbsd.org. MX cvs.openbsd.org. 
zaurus.openbsd.org. A 199.185.137.50 
zeus.openbsd.org. CNAME 
openbsd.org. SOA zeus.theos.com. root.theos.com. 
" /></port> +<port protocol="tcp" portid="80"><state state="open" reason="syn-ack" reason_ttl="48"/><service name="http" product="Apache httpd" method="probed" conf="10" /><script id="robots.txt" output="/cgi-bin/ /faq/new/ 
/donations.html " /><script id="HTML title" output="OpenBSD" /></port> +<port protocol="tcp" portid="7326"><state state="open" reason="syn-ack" reason_ttl="45"/><service name="icb" servicefp="SF-Port7326-TCP:V=4.53%I=7%D=1/27%Time=479D24BC%P=i686-pc-linux-gnu%r(NULL
SF:,43,"Bj1\x01cvs\.openbsd\.org\x01Darkside\x20Server\x20version\x201\.3\
SF:.221\x20\+\x20pain,\x20v0\.100\0")%r(GenericLines,43,"Bj1\x01cvs\.openb
SF:sd\.org\x01Darkside\x20Server\x20version\x201\.3\.221\x20\+\x20pain,\x2
SF:0v0\.100\0")%r(GetRequest,43,"Bj1\x01cvs\.openbsd\.org\x01Darkside\x20S
SF:erver\x20version\x201\.3\.221\x20\+\x20pain,\x20v0\.100\0")%r(HTTPOptio
SF:ns,43,"Bj1\x01cvs\.openbsd\.org\x01Darkside\x20Server\x20version\x201\.
SF:3\.221\x20\+\x20pain,\x20v0\.100\0")%r(RTSPRequest,43,"Bj1\x01cvs\.open
SF:bsd\.org\x01Darkside\x20Server\x20version\x201\.3\.221\x20\+\x20pain,\x
SF:20v0\.100\0")%r(RPCCheck,43,"Bj1\x01cvs\.openbsd\.org\x01Darkside\x20Se
SF:rver\x20version\x201\.3\.221\x20\+\x20pain,\x20v0\.100\0")%r(DNSVersion
SF:BindReq,43,"Bj1\x01cvs\.openbsd\.org\x01Darkside\x20Server\x20version\x
SF:201\.3\.221\x20\+\x20pain,\x20v0\.100\0")%r(DNSStatusRequest,43,"Bj1\x0
SF:1cvs\.openbsd\.org\x01Darkside\x20Server\x20version\x201\.3\.221\x20\+\
SF:x20pain,\x20v0\.100\0")%r(Help,43,"Bj1\x01cvs\.openbsd\.org\x01Darkside
SF:\x20Server\x20version\x201\.3\.221\x20\+\x20pain,\x20v0\.100\0")%r(SSLS
SF:essionReq,43,"Bj1\x01cvs\.openbsd\.org\x01Darkside\x20Server\x20version
SF:\x201\.3\.221\x20\+\x20pain,\x20v0\.100\0")%r(SMBProgNeg,43,"Bj1\x01cvs
SF:\.openbsd\.org\x01Darkside\x20Server\x20version\x201\.3\.221\x20\+\x20p
SF:ain,\x20v0\.100\0")%r(X11Probe,43,"Bj1\x01cvs\.openbsd\.org\x01Darkside
SF:\x20Server\x20version\x201\.3\.221\x20\+\x20pain,\x20v0\.100\0")%r(Four
SF:OhFourRequest,43,"Bj1\x01cvs\.openbsd\.org\x01Darkside\x20Server\x20ver
SF:sion\x201\.3\.221\x20\+\x20pain,\x20v0\.100\0")%r(LPDString,6C,"Bj1\x01
SF:cvs\.openbsd\.org\x01Darkside\x20Server\x20version\x201\.3\.221\x20\+\x
SF:2" method="table" conf="3" /></port> +</ports> +<os><portused state="open" proto="tcp" portid="21" /> +<portused state="closed" proto="tcp" portid="22" /> +<portused state="closed" proto="udp" portid="34307" /> +<osclass type="VoIP gateway" vendor="Netcomm" osfamily="embedded" accuracy="87" /> +<osmatch name="Netcomm V300 VoIP gateway" accuracy="87" line="15324"/> +<osfingerprint fingerprint="SCAN(V=4.53%D=1/27%OT=21%CT=22%CU=34307%PV=N%DS=21%G=N%TM=479D25ED%P=i686-pc-linux-gnu)
SEQ(SP=103%GCD=1%ISR=10B%TI=RD%TS=21)
OPS(O1=M5B4NNSNW0NNT11%O2=M5B4NNSNW0NNT11%O3=M5B4NW0NNT11%O4=M5B4NNSNW0NNT11%O5=M5B4NNSNW0NNT11%O6=M5B4NNSNNT11)
WIN(W1=4000%W2=4000%W3=4000%W4=4000%W5=4000%W6=4000)
ECN(R=Y%DF=Y%T=42%W=4000%O=M5B4NNSNW0%CC=N%Q=)
ECN(R=N)
T1(R=Y%DF=Y%T=42%S=O%A=S+%F=AS%RD=0%Q=)
T2(R=N)
T3(R=N)
T4(R=N)
T5(R=Y%DF=Y%T=43%W=0%S=A%A=S+%F=AR%O=%RD=0%Q=)
T5(R=N)
T6(R=N)
T7(R=N)
U1(R=Y%DF=N%T=101%TOS=0%IPL=38%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=ACD0%RUL=G%RUD=G)
IE(R=Y%DFI=S%T=104%TOSI=S%CD=S%SI=S%DLI=S)
IE(R=Y%DFI=S%T=101%TOSI=S%CD=S%SI=S%DLI=S)
" /> +</os> +<distance value="21" /> +<trace port="21" proto="tcp"> +<hop ttl="1" rtt="3.40" ipaddr="192.168.254.254"/> +<hop ttl="2" rtt="33.50" ipaddr="200.217.89.32"/> +<hop ttl="3" rtt="35.53" ipaddr="200.217.30.250" host="gigabitethernet5-1.80-cto-rn-rotd-02.telemar.net.br"/> +<hop ttl="4" rtt="52.95" ipaddr="200.97.65.245" host="pos9-1-bvg-pe-rotd-02.telemar.net.br"/> +<hop ttl="5" rtt="53.04" ipaddr="200.223.131.21" host="pos6-0-bvg-pe-rotn-01.telemar.net.br"/> +<hop ttl="6" rtt="87.46" ipaddr="200.223.43.245"/> +<hop ttl="7" rtt="208.03" ipaddr="200.223.131.138" host="PO12-0.ARC-RJ-ROTD-03.telemar.net.br"/> +<hop ttl="8" rtt="199.96" ipaddr="144.228.186.117" host="sl-st22-mia-13-0-0.sprintlink.net"/> +<hop ttl="9" rtt="198.19" ipaddr="144.232.2.205" host="sl-bb20-mia-10-0-0.sprintlink.net"/> +<hop ttl="10" rtt="203.13" ipaddr="144.232.2.203" host="sl-bb22-mia-3-0-0.sprintlink.net"/> +<hop ttl="11" rtt="198.98" ipaddr="144.232.18.216" host="sl-crs2-atl-0-0-0-1.sprintlink.net"/> +<hop ttl="12" rtt="289.94" ipaddr="144.232.9.125" host="sl-bb20-nsh-15-0-0.sprintlink.net"/> +<hop ttl="13" rtt="206.40" ipaddr="144.232.23.129"/> +<hop ttl="14" rtt="214.70" ipaddr="144.232.9.126" host="sl-bb25-chi-12-0-0.sprintlink.net"/> +<hop ttl="15" rtt="259.42" ipaddr="144.232.20.156" host="sl-bb21-sea-1-0.sprintlink.net"/> +<hop ttl="16" rtt="260.75" ipaddr="144.232.6.134" host="sl-gw14-sea-9-0.sprintlink.net"/> +<hop ttl="17" rtt="263.99" ipaddr="144.232.219.238" host="sl-callnet-49-0.sprintlink.net"/> +<hop ttl="18" rtt="282.49" ipaddr="204.50.128.13" host="p3-0-S1.bb1.cal1.rogerstelecom.net"/> +<hop ttl="19" rtt="273.89" ipaddr="204.50.251.141" host="g5-1-S1.tls2.cal1.rogerstelecom.net"/> +<hop ttl="20" rtt="277.01" ipaddr="207.107.204.178" host="Z-s4-0-0-5-0-S1.tls2.cal1.rogerstelecom.net"/> +<hop ttl="21" rtt="280.83" ipaddr="199.185.230.2" host="pf.openbsd.org"/> +<hop ttl="22" rtt="280.60" ipaddr="199.185.137.3" host="cvs.openbsd.org"/> +</trace> +<times srtt="326085" rttvar="47769" to="517161" /> +</host> +<taskbegin task="SYN Stealth Scan" time="1201481197" /> +<taskprogress task="SYN Stealth Scan" time="1201481228" percent="9.14" remaining="298" etc="1201481526" /> +<taskend task="SYN Stealth Scan" time="1201481433" extrainfo="5142 total ports" /> +<taskbegin task="Service scan" time="1201481433" /> +<taskend task="Service scan" time="1201481455" extrainfo="12 services on 3 hosts" /> +<taskbegin task="Traceroute" time="1201481472" /> +<taskend task="Traceroute" time="1201481512" /> +<taskbegin task="Traceroute" time="1201481512" /> +<taskend task="Traceroute" time="1201481523" /> +<taskbegin task="Parallel DNS resolution of 46 hosts." time="1201481523" /> +<taskend task="Parallel DNS resolution of 46 hosts." time="1201481536" /> +<taskbegin task="System CNAME DNS resolution of 1 host." time="1201481536" /> +<taskend task="System CNAME DNS resolution of 1 host." time="1201481536" /> +<taskbegin task="SCRIPT ENGINE" time="1201481536" /> +<taskend task="SCRIPT ENGINE" time="1201481569" /> +<host><status state="up" reason="reset"/> +<address addr="204.152.190.12" addrtype="ipv4" /> +<hostnames><hostname name="www.netbsd.org" type="PTR" /></hostnames> +<ports><extraports state="closed" count="1705"> +<extrareasons reason="resets" count="1705"/> +</extraports> +<port protocol="tcp" portid="22"><state state="open" reason="syn-ack" reason_ttl="46"/><service name="ssh" product="OpenSSH" version="4.4" extrainfo="NetBSD 20061114; protocol 2.0" ostype="NetBSD" method="probed" conf="10" /></port> +<port protocol="tcp" portid="25"><state state="open" reason="syn-ack" reason_ttl="46"/><service name="smtp" product="Postfix smtpd" hostname=" narn.NetBSD.org" method="probed" conf="10" /><script id="SMTP" output="HELP with errors or timeout. Enable --script-trace to see what is happening." /></port> +<port protocol="tcp" portid="80"><state state="open" reason="syn-ack" reason_ttl="46"/><service name="http" product="Apache httpd" version="2.0.61" extrainfo="(Unix) mod_ssl/2.0.61 DAV/2 mod_fastcgi/2.4.2 mod_apreq2-20051231/2.6.0" method="probed" conf="10" /><script id="HTML title" output="The NetBSD Project" /></port> +<port protocol="tcp" portid="443"><state state="open" reason="syn-ack" reason_ttl="46"/><service name="http" product="Apache httpd" version="2.0.61" extrainfo="mod_ssl/2.0.61 DAV/2 mod_fastcgi/2.4.2 mod_apreq2-20051231/2.6.0" hostname="rt.NetBSD.org" method="probed" conf="10" /><script id="HTML title" output="400 Bad Request" /><script id="SSLv2" output="server still supports SSLv2
	SSL2_DES_192_EDE3_CBC_WITH_MD5
	SSL2_IDEA_128_CBC_WITH_MD5
	SSL2_RC2_CBC_128_CBC_WITH_MD5
	SSL2_RC4_128_WITH_MD5
	SSL2_DES_64_CBC_WITH_MD5
	SSL2_RC2_CBC_128_CBC_WITH_MD5
	SSL2_RC4_128_EXPORT40_WITH_MD5
" /></port> +<port protocol="tcp" portid="871"><state state="open" reason="syn-ack" reason_ttl="46"/><service name="supfilesrv" method="table" conf="3" /></port> +<port protocol="tcp" portid="874"><state state="open" reason="syn-ack" reason_ttl="46"/><service name="rsync" extrainfo="protocol version 29" method="probed" conf="10" /></port> +<port protocol="tcp" portid="1720"><state state="filtered" reason="no-response" reason_ttl="0"/><service name="H.323/Q.931" method="table" conf="3" /></port> +<port protocol="tcp" portid="1984"><state state="open" reason="syn-ack" reason_ttl="46"/><service name="tcpwrapped" method="probed" conf="8" /></port> +<port protocol="tcp" portid="2022"><state state="open" reason="syn-ack" reason_ttl="46"/><service name="ssh" product="OpenSSH" version="4.4" extrainfo="NetBSD 20061114; protocol 2.0" ostype="NetBSD" method="probed" conf="10" /></port> +</ports> +<os><portused state="open" proto="tcp" portid="22" /> +<portused state="closed" proto="tcp" portid="1" /> +<portused state="closed" proto="udp" portid="32193" /> +<osclass type="WAP" vendor="Apple" osfamily="NetBSD" osgen="4.X" accuracy="90" /> +<osclass type="general purpose" vendor="NetBSD" osfamily="NetBSD" osgen="4.X" accuracy="90" /> +<osmatch name="Apple AirPort Extreme WAP (runs NetBSD)" accuracy="90" line="1382"/> +<osmatch name="NetBSD 4.99.4 (x86)" accuracy="90" line="15307"/> +<osfingerprint fingerprint="SCAN(V=4.53%D=1/27%OT=22%CT=1%CU=32193%PV=N%DS=14%G=N%TM=479D2761%P=i686-pc-linux-gnu)
SEQ(SP=D7%GCD=1%ISR=E1%TI=I%II=I%SS=O%TS=0)
SEQ(SP=DD%GCD=1%ISR=DE%TS=0)
OPS(O1=M5B4NW0NNT01SNN%O2=M5B4NW0NNT01SNN%O3=M5B4NW0NNT01%O4=M5B4NW0NNT01SNN%O5=M5B4NW0NNT01SNN%O6=M5B4NNT01SNN)
WIN(W1=8000%W2=8000%W3=8000%W4=8000%W5=8000%W6=8000)
ECN(R=Y%DF=Y%T=3C%W=8000%O=M5B4NW0SNN%CC=N%Q=)
T1(R=Y%DF=Y%T=3C%S=O%A=S+%F=AS%RD=0%Q=)
T2(R=N)
T3(R=Y%DF=Y%T=3C%W=8000%S=O%A=S+%F=AS%O=M5B4NW0NNT01SNN%RD=0%Q=)
T4(R=Y%DF=N%T=3C%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)
T5(R=Y%DF=N%T=3C%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)
T6(R=Y%DF=N%T=3C%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)
T7(R=Y%DF=N%T=3C%W=0%S=Z%A=S%F=AR%O=%RD=0%Q=)
U1(R=Y%DF=N%T=FB%TOS=0%IPL=38%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=B43D%RUL=G%RUD=G)
IE(R=Y%DFI=N%T=FB%TOSI=Z%CD=S%SI=S%DLI=S)
" /> +</os> +<distance value="14" /> +<tcpsequence index="221" class="unknown class" difficulty="Good luck!" values="CED51C9E,D2626FBA,D39DAEE3,D423A220,D782D901,D8072C18" /> +<ipidsequence class="Busy server or unknown class" values="712C,713A,713C,7142,7145,7146" /> +<tcptssequence class="zero timestamp" values="0,0,0,0,0,0" /> +<trace port="22" proto="tcp"> +<hop ttl="1" rtt="1.07" ipaddr="192.168.254.254"/> +<hop ttl="2" rtt="19.01" ipaddr="200.217.89.32"/> +<hop ttl="3" rtt="23.34" ipaddr="200.217.30.210" host="gigabitethernet6-1.90-cto-rn-rotd-02.telemar.net.br"/> +<hop ttl="4" rtt="44.72" ipaddr="200.97.65.245" host="pos9-1-bvg-pe-rotd-02.telemar.net.br"/> +<hop ttl="5" rtt="45.01" ipaddr="200.223.131.21" host="pos6-0-bvg-pe-rotn-01.telemar.net.br"/> +<hop ttl="6" rtt="87.41" ipaddr="200.223.43.245"/> +<hop ttl="7" rtt="242.32" ipaddr="200.223.131.138" host="PO12-0.ARC-RJ-ROTD-03.telemar.net.br"/> +<hop ttl="8" rtt="197.53" ipaddr="208.51.142.233" host="so-6-2-0.ar2.MIA1.gblx.net"/> +<hop ttl="10" rtt="329.86" ipaddr="64.215.195.22"/> +<hop ttl="13" rtt="250.62" ipaddr="149.20.65.32" host="int-1-2-0.r2.sfo2.isc.org"/> +<hop ttl="14" rtt="246.57" ipaddr="149.20.65.1" host="int-0-2.r1.sql1.isc.org"/> +<hop ttl="15" rtt="252.50" ipaddr="204.152.190.12" host="www.netbsd.org"/> +</trace> +<times srtt="266011" rttvar="14051" to="322215" /> +</host> +<host><status state="up" reason="reset"/> +<address addr="72.14.207.99" addrtype="ipv4" /> +<hostnames><hostname name="eh-in-f99.google.com" type="PTR" /></hostnames> +<ports><extraports state="filtered" count="1710"> +<extrareasons reason="no-responses" count="1710"/> +</extraports> +<port protocol="tcp" portid="80"><state state="open" reason="syn-ack" reason_ttl="49"/><service name="http" product="Google httpd" version="1.3" extrainfo="GFE" ostype="Linux" method="probed" conf="10" /><script id="HTML title" output="302 Moved" /></port> +<port protocol="tcp" portid="113"><state state="closed" reason="reset" reason_ttl="245"/><service name="auth" method="table" conf="3" /></port> +<port protocol="tcp" portid="179"><state state="closed" reason="reset" reason_ttl="240"/><service name="bgp" method="table" conf="3" /></port> +<port protocol="tcp" portid="443"><state state="open" reason="syn-ack" reason_ttl="49"/><service name="http" product="Google httpd" version="1.3" extrainfo="GFE" ostype="Linux" tunnel="ssl" method="probed" conf="10" /><script id="SSLv2" output="server still supports SSLv2
	SSL2_DES_192_EDE3_CBC_WITH_MD5
	SSL2_RC2_CBC_128_CBC_WITH_MD5
	SSL2_RC4_128_WITH_MD5
	SSL2_DES_64_CBC_WITH_MD5
	SSL2_RC2_CBC_128_CBC_WITH_MD5
	SSL2_RC4_128_EXPORT40_WITH_MD5
" /><script id="HTML title" output="302 Moved" /></port> +</ports> +<os><portused state="open" proto="tcp" portid="80" /> +<portused state="closed" proto="tcp" portid="113" /> +<osfingerprint fingerprint="SCAN(V=4.53%D=1/27%OT=80%CT=113%CU=%PV=N%DS=14%G=N%TM=479D2761%P=i686-pc-linux-gnu)
SEQ(SP=D4%GCD=1%ISR=D8%TI=RD%TS=21)
SEQ(SP=C4%GCD=1%ISR=C5%TI=RD%TS=20)
OPS(O1=M596ST11NW0%O2=M596ST11NW0%O3=M596NNT11NW0%O4=M596ST11NW0%O5=M596ST11NW0%O6=M596ST11)
WIN(W1=1628%W2=1628%W3=1628%W4=1628%W5=1628%W6=1628)
ECN(R=Y%DF=N%TG=40%W=1658%O=M596NNSNW0%CC=N%Q=)
T1(R=Y%DF=N%TG=40%S=O%A=S+%F=AS%RD=0%Q=)
T2(R=N)
T3(R=Y%DF=N%TG=40%W=1628%S=O%A=S+%F=AS%O=M596ST11NW0%RD=0%Q=)
T4(R=Y%DF=N%TG=FF%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)
T5(R=Y%DF=N%TG=FF%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)
T6(R=Y%DF=N%TG=FF%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)
T7(R=Y%DF=N%TG=FF%W=0%S=Z%A=S%F=AR%O=%RD=0%Q=)
T7(R=Y%DF=N%TG=FF%W=0%S=Z%A=S%F=AR%O=%RD=0%Q=R)
U1(R=N)
IE(R=N)
" /> +</os> +<uptime seconds="105" lastboot="Sun Jan 27 21:51:04 2008" /> +<distance value="14" /> +<tcpsequence index="196" class="unknown class" difficulty="Good luck!" values="CBEEB360,CC4F1B1F,CD1DFB63,CD000A94,CCEE5704,CD2469F3" /> +<ipidsequence class="Randomized" values="5AA6,7CDB,65B,1CCC,65C5,65C" /> +<tcptssequence class="other" values="837BC3C0,2208A10,8375A88B,8372C162,837C9852,8375A8CA" /> +<trace port="80" proto="tcp"> +<hop ttl="1" rtt="1.08" ipaddr="192.168.254.254"/> +<hop ttl="2" rtt="20.26" ipaddr="200.217.89.32"/> +<hop ttl="3" rtt="28.64" ipaddr="200.217.30.210" host="gigabitethernet6-1.90-cto-rn-rotd-02.telemar.net.br"/> +<hop ttl="4" rtt="47.95" ipaddr="200.97.65.245" host="pos9-1-bvg-pe-rotd-02.telemar.net.br"/> +<hop ttl="5" rtt="47.54" ipaddr="200.223.131.21" host="pos6-0-bvg-pe-rotn-01.telemar.net.br"/> +<hop ttl="6" rtt="87.51" ipaddr="200.223.43.245"/> +<hop ttl="7" rtt="116.31" ipaddr="200.223.43.242"/> +<hop ttl="8" rtt="99.86" ipaddr="74.125.51.29"/> +<hop ttl="9" rtt="115.52" ipaddr="209.85.250.242"/> +<hop ttl="10" rtt="236.86" ipaddr="209.85.249.199"/> +<hop ttl="11" rtt="232.95" ipaddr="216.239.43.146"/> +<hop ttl="12" rtt="252.37" ipaddr="66.249.94.92"/> +<hop ttl="13" rtt="239.82" ipaddr="72.14.236.130"/> +<hop ttl="14" rtt="254.89" ipaddr="72.14.207.99" host="eh-in-f99.google.com"/> +</trace> +<times srtt="116825" rttvar="14467" to="174693" /> +</host> +<host><status state="up" reason="reset"/> +<address addr="72.14.253.83" addrtype="ipv4" /> +<hostnames><hostname name="po-in-f83.google.com" type="PTR" /></hostnames> +<ports><extraports state="filtered" count="1710"> +<extrareasons reason="no-responses" count="1710"/> +</extraports> +<port protocol="tcp" portid="80"><state state="open" reason="syn-ack" reason_ttl="46"/><service name="http" product="Google httpd" version="1.3" extrainfo="GFE" ostype="Linux" method="probed" conf="10" /><script id="HTML title" output="302 Moved" /><script id="robots.txt" output="/news?output=xhtml& /search /groups /images 
/catalogs /catalogues /news /nwshp /? /addurl/image? 
/pagead/ /relpage/ /relcontent /sorry/ /imgres 
/keyword/ /u/ /univ/ /cobrand /custom 
/advanced_group_search /advanced_search /googlesite /preferences 
/setprefs /swr /url /default /m? /m/search? /wml? 
/wml/search? /xhtml? /xhtml/search? /xml? /imode? 
/imode/search? /jsky? /jsky/search? /pda? /pda/search? 
/sprint_xhtml /sprint_wml /pqa /palm /gwt/ /purchases /hws 
/bsd? /linux? /mac? /microsoft? /unclesam? 
/answers/search?q= /local? /local_url /froogle? /products? 
/froogle_ /product_ /products_ /print /books /patents? 
/scholar? /complete /sponsoredlinks /videosearch? 
/videopreview? /videoprograminfo? /maps? /mapstt? /mapslt? 
/translate? /ie? /sms/demo? /katrina? /blogsearch? 
/blogsearch/ /blogsearch_feeds /advanced_blog_search 
/reader/ /uds/ /chart? /transit? /mbd? /extern_js/ 
/calendar/feeds/ /calendar/ical/ /cl2/feeds/ /cl2/ical/ 
/coop/directory /coop/manage /trends? /trends/music? 
/notebook/search? /music /browsersync /call /archivesearch? 
/archivesearch/url /archivesearch/advanced_search 
/base/search? /base/reportbadoffer /base/s2 
/urchin_test/ /movies? /codesearch? 
/codesearch/feeds/search? /wapsearch? /safebrowsing /reviews/search? 
/orkut/albums /jsapi /views? /c/ /cbk 
/recharge/dashboard/car /recharge/dashboard/static/ /translate_c? 
/s2 /transconsole/portal/ /gcc/ /aclk /cse? 
/tbproxy/ " /></port> +<port protocol="tcp" portid="113"><state state="closed" reason="reset" reason_ttl="246"/><service name="auth" method="table" conf="3" /></port> +<port protocol="tcp" portid="179"><state state="closed" reason="reset" reason_ttl="237"/><service name="bgp" method="table" conf="3" /></port> +<port protocol="tcp" portid="443"><state state="open" reason="syn-ack" reason_ttl="46"/><service name="https" tunnel="ssl" method="table" conf="3" /><script id="HTML title" output="302 Moved" /><script id="SSLv2" output="server still supports SSLv2
	SSL2_DES_192_EDE3_CBC_WITH_MD5
	SSL2_RC2_CBC_128_CBC_WITH_MD5
	SSL2_RC4_128_WITH_MD5
	SSL2_DES_64_CBC_WITH_MD5
	SSL2_RC2_CBC_128_CBC_WITH_MD5
	SSL2_RC4_128_EXPORT40_WITH_MD5
" /></port> +</ports> +<os><portused state="open" proto="tcp" portid="80" /> +<portused state="closed" proto="tcp" portid="113" /> +<osfingerprint fingerprint="SCAN(V=4.53%D=1/27%OT=80%CT=113%CU=%PV=N%DS=14%G=N%TM=479D2761%P=i686-pc-linux-gnu)
SEQ(SP=105%GCD=1%ISR=10A%TI=RD%TS=21)
SEQ(SP=105%GCD=1%ISR=106%TI=RD%TS=21)
OPS(O1=M596ST11NW6%O2=M596ST11NW6%O3=M596NNT11NW6%O4=M596ST11NW6%O5=M596ST11NW6%O6=M596ST11)
WIN(W1=1628%W2=1628%W3=1628%W4=1628%W5=1628%W6=1628)
ECN(R=Y%DF=N%TG=40%W=1658%O=M596NNSNW6%CC=N%Q=)
T1(R=Y%DF=N%TG=40%S=O%A=S+%F=AS%RD=0%Q=)
T2(R=N)
T3(R=Y%DF=N%TG=40%W=1628%S=O%A=S+%F=AS%O=M596ST11NW6%RD=0%Q=)
T4(R=Y%DF=N%TG=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)
T5(R=Y%DF=N%TG=FF%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)
T5(R=Y%DF=N%TG=FF%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=R)
T6(R=Y%DF=N%TG=FF%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)
T7(R=Y%DF=N%TG=FF%W=0%S=Z%A=S%F=AR%O=%RD=0%Q=)
U1(R=N)
IE(R=N)
" /> +</os> +<uptime seconds="105" lastboot="Sun Jan 27 21:51:04 2008" /> +<distance value="14" /> +<tcpsequence index="261" class="unknown class" difficulty="Good luck!" values="6ACD6329,921C6817,E6012864,90104A22,90651704,E5CE7F5A" /> +<ipidsequence class="Randomized" values="D6CC,94A,2253,2AE5,A75E,2254" /> +<tcptssequence class="other" values="52F3E255,22566720,D6046C6E,D4792BF0,22539966,D6046E1B" /> +<trace port="80" proto="tcp"> +<hop ttl="1" rtt="1.60" ipaddr="192.168.254.254"/> +<hop ttl="2" rtt="25.93" ipaddr="200.217.89.32"/> +<hop ttl="3" rtt="33.57" ipaddr="200.217.30.250" host="gigabitethernet5-1.80-cto-rn-rotd-02.telemar.net.br"/> +<hop ttl="4" rtt="47.18" ipaddr="200.97.65.245" host="pos9-1-bvg-pe-rotd-02.telemar.net.br"/> +<hop ttl="5" rtt="47.91" ipaddr="200.223.131.21" host="pos6-0-bvg-pe-rotn-01.telemar.net.br"/> +<hop ttl="6" rtt="87.59" ipaddr="200.223.43.245"/> +<hop ttl="7" rtt="116.58" ipaddr="200.223.43.242"/> +<hop ttl="8" rtt="117.01" ipaddr="74.125.51.5"/> +<hop ttl="9" rtt="117.63" ipaddr="209.85.250.242"/> +<hop ttl="10" rtt="427.06" ipaddr="209.85.249.199"/> +<hop ttl="11" rtt="279.22" ipaddr="72.14.236.213"/> +<hop ttl="12" rtt="305.96" ipaddr="209.85.130.22"/> +<hop ttl="13" rtt="312.64" ipaddr="216.239.46.50"/> +<hop ttl="14" rtt="291.35" ipaddr="209.85.250.144"/> +<hop ttl="15" rtt="294.36" ipaddr="216.239.48.143"/> +<hop ttl="16" rtt="306.89" ipaddr="209.85.251.153"/> +<hop ttl="17" rtt="291.39" ipaddr="74.125.30.170"/> +<hop ttl="18" rtt="293.11" ipaddr="74.125.30.42"/> +<hop ttl="19" rtt="312.18" ipaddr="72.14.253.83" host="po-in-f83.google.com"/> +</trace> +<times srtt="244322" rttvar="98383" to="637854" /> +</host> +<runstats><finished time="1201481569" timestr="Sun Jan 27 21:52:49 2008"/><hosts up="8" down="0" total="8" /> +<!-- Nmap done at Sun Jan 27 21:52:49 2008; 8 IP addresses (8 hosts up) scanned in 2567.750 seconds --> +</runstats></nmaprun> diff --git a/zenmap/radialnet/util/__init__.py b/zenmap/radialnet/util/__init__.py new file mode 100644 index 0000000..c314dd7 --- /dev/null +++ b/zenmap/radialnet/util/__init__.py @@ -0,0 +1,56 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ diff --git a/zenmap/radialnet/util/drawing.py b/zenmap/radialnet/util/drawing.py new file mode 100644 index 0000000..0cc3763 --- /dev/null +++ b/zenmap/radialnet/util/drawing.py @@ -0,0 +1,67 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + + +def cairo_to_gdk_color(color): + """ + """ + new_color = list(range(len(color))) + + for i in range(len(color)): + new_color[i] = int(color[i] * 65535) + + return new_color diff --git a/zenmap/radialnet/util/geometry.py b/zenmap/radialnet/util/geometry.py new file mode 100644 index 0000000..109443b --- /dev/null +++ b/zenmap/radialnet/util/geometry.py @@ -0,0 +1,152 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +import math + + +def is_in_square(point, half_side, center=(0, 0)): + """ + """ + x, y = point + a, b = center + + if a + half_side >= x >= a - half_side: + if b + half_side >= y >= b - half_side: + return True + + return False + + +def is_in_circle(point, radius=1, center=(0, 0)): + """ + """ + x, y = point + a, b = center + + if ((x - a) ** 2 + (y - b) ** 2) <= (radius ** 2): + return True + + return False + + +def atan_scale(point, scale_ceil): + """ + """ + new_point = float(10.0 * point / scale_ceil) - 5 + return math.atan(abs(new_point)) + + +def normalize_angle(angle): + """ + """ + new_angle = 360.0 * (float(angle / 360) - int(angle / 360)) + + if new_angle < 0: + return 360 + new_angle + + return new_angle + + +def is_between_angles(a, b, c): + """ + """ + a = normalize_angle(a) + b = normalize_angle(b) + c = normalize_angle(c) + + if a > b: + + if c >= a and c <= 360 or c <= b: + return True + + return False + + else: + + if c >= a and c <= b: + return True + + return False + + +def angle_distance(a, b): + """ + """ + distance = abs(normalize_angle(a) - normalize_angle(b)) + + if distance > 180: + return 360 - distance + + return distance + + +def calculate_short_path(iangle, fangle): + """ + """ + if iangle - fangle > 180: + fangle += 360 + + if iangle - fangle < -180: + fangle -= 360 + + return iangle, fangle + + +def angle_from_object(distance, size): + """ + """ + return math.degrees(math.atan2(size / 2.0, distance)) diff --git a/zenmap/radialnet/util/integration.py b/zenmap/radialnet/util/integration.py new file mode 100644 index 0000000..6efd9e8 --- /dev/null +++ b/zenmap/radialnet/util/integration.py @@ -0,0 +1,269 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +from radialnet.core.Graph import Graph +from radialnet.gui.RadialNet import NetNode + +import math + + +COLORS = [(0.0, 1.0, 0.0), + (1.0, 1.0, 0.0), + (1.0, 0.0, 0.0)] + +BASE_RADIUS = 5.5 +NONE_RADIUS = 4.5 + + +def set_node_info(node, host): + """ + """ + node.set_host(host) + + radius = BASE_RADIUS + 2 * math.log( + node.get_info("number_of_open_ports") + 1) + + node.set_draw_info({"color": COLORS[node.get_info("vulnerability_score")], + "radius": radius}) + + +class TracerouteHostInfo(object): + """This is a minimal implementation of HostInfo, sufficient to + represent the information in an intermediate traceroute hop.""" + def __init__(self): + self.ip = None + self.ipv6 = None + self.mac = None + self.hostname = None + self.ports = [] + self.extraports = [] + self.osmatches = [] + + def get_hostname(self): + return self.hostname + + def get_best_osmatch(self): + if not self.osmatches: + return None + + def osmatch_key(osmatch): + try: + return -float(osmatch["accuracy"]) + except ValueError: + return 0 + + return sorted(self.osmatches, key=osmatch_key)[0] + + hostnames = property(lambda self: self.hostname and [self.hostname] or []) + + +def find_hop_by_ttl(hops, ttl): + assert ttl >= 0, "ttl must be non-negative" + if ttl == 0: # Same machine (i.e. localhost) + return {"ipaddr": "127.0.0.1/8"} + for h in hops: + if ttl == int(h["ttl"]): + return h + return None + + +def make_graph_from_hosts(hosts): + #hosts = parser.get_root().search_children('host', deep=True) + graph = Graph() + nodes = list() + node_cache = {} + ancestor_node_cache = {} + descendant_node_cache = {} + + # Setting initial reference host + main_node = NetNode() + nodes.append(main_node) + + localhost = TracerouteHostInfo() + localhost.ip = {"addr": "127.0.0.1/8", "type": "ipv4"} + localhost.hostname = "localhost" + main_node.set_host(localhost) + main_node.set_draw_info( + {"valid": True, "color": (0, 0, 0), "radius": NONE_RADIUS}) + + #Save endpoints for attaching scanned hosts to + endpoints = {} + # For each host in hosts just mount the graph + for host in hosts: + trace = host.trace + endpoints[host] = nodes[0] + hops = trace.get("hops") + + # If host has traceroute information mount graph + if hops is not None and len(hops) > 0: + prev_node = nodes[0] + hops = trace.get("hops", []) + ttls = [int(hop["ttl"]) for hop in hops] + + # Getting nodes of host by ttl + for ttl in range(1, max(ttls) + 1): + if ttl in ttls: + hop = find_hop_by_ttl(hops, ttl) + node = node_cache.get(hop["ipaddr"]) + if node is None: + node = NetNode() + nodes.append(node) + + hop_host = TracerouteHostInfo() + hop_host.ip = { + "addr": hop["ipaddr"], + "type": "", + "vendor": "" + } + node.set_draw_info({"valid": True}) + node.set_draw_info({"color": (1, 1, 1), + "radius": NONE_RADIUS}) + + if hop["host"] != "": + hop_host.hostname = hop["host"] + + node.set_host(hop_host) + + node_cache[node.get_info("ip")] = node + + rtt = hop["rtt"] + if rtt != "--": + graph.set_connection(node, prev_node, float(rtt)) + else: + graph.set_connection(node, prev_node) + else: + # Add an "anonymous" node only if there isn't already a + # node equivalent to it (i.e. at same distance from the + # previous "real" node) + + pre_hop = None + pre_hop_distance = 0 + for i in range(1, ttl + 1): + pre_hop = find_hop_by_ttl(hops, ttl - i) + if pre_hop is not None: + pre_hop_distance = i + break + + post_hop = None + post_hop_distance = 0 + for i in range(1, max(ttls) - ttl): + post_hop = find_hop_by_ttl(hops, ttl + i) + if post_hop is not None: + post_hop_distance = i + break + + assert pre_hop is not None, \ + "pre_hop should have become localhost if nothing else" # noqa + + ancestor_key = (pre_hop["ipaddr"], pre_hop_distance) + descendant_key = None + if post_hop is not None: + descendant_key = \ + (post_hop["ipaddr"], post_hop_distance) + + if ancestor_key in ancestor_node_cache: + node = ancestor_node_cache[ancestor_key] + elif (descendant_key is not None and + descendant_key in descendant_node_cache): + node = descendant_node_cache[descendant_key] + graph.set_connection(node, prev_node) + else: + node = NetNode() + nodes.append(node) + + node.set_draw_info({"valid": False}) + node.set_draw_info( + {"color": (1, 1, 1), "radius": NONE_RADIUS}) + + graph.set_connection(node, prev_node) + + ancestor_node_cache[ancestor_key] = node + if descendant_key is not None: + descendant_node_cache[descendant_key] = node + + prev_node = node + endpoints[host] = node + + # For each fully scanned host + for host in hosts: + ip = host.ip + if ip is None: + ip = host.ipv6 + + node = node_cache.get(ip["addr"]) + if node is None: + node = NetNode() + nodes.append(node) + + node.set_draw_info({"no_route": True}) + + graph.set_connection(node, endpoints[host]) + + node.set_draw_info({"valid": True}) + node.set_draw_info({"scanned": True}) + set_node_info(node, host) + node_cache[node.get_info("ip")] = node + + graph.set_nodes(nodes) + graph.set_main_node(main_node) + + return graph + + +def make_graph_from_nmap_parser(parser): + return make_graph_from_hosts( + parser.get_root().search_children('host', deep=True)) diff --git a/zenmap/radialnet/util/misc.py b/zenmap/radialnet/util/misc.py new file mode 100644 index 0000000..10f24b9 --- /dev/null +++ b/zenmap/radialnet/util/misc.py @@ -0,0 +1,115 @@ +# vim: set fileencoding=utf-8 : + +# ***********************IMPORTANT NMAP LICENSE TERMS************************ +# * +# * The Nmap Security Scanner is (C) 1996-2023 Nmap Software LLC ("The Nmap +# * Project"). Nmap is also a registered trademark of the Nmap Project. +# * +# * This program is distributed under the terms of the Nmap Public Source +# * License (NPSL). The exact license text applying to a particular Nmap +# * release or source code control revision is contained in the LICENSE +# * file distributed with that version of Nmap or source code control +# * revision. More Nmap copyright/legal information is available from +# * https://nmap.org/book/man-legal.html, and further information on the +# * NPSL license itself can be found at https://nmap.org/npsl/ . This +# * header summarizes some key points from the Nmap license, but is no +# * substitute for the actual license text. +# * +# * Nmap is generally free for end users to download and use themselves, +# * including commercial use. It is available from https://nmap.org. +# * +# * The Nmap license generally prohibits companies from using and +# * redistributing Nmap in commercial products, but we sell a special Nmap +# * OEM Edition with a more permissive license and special features for +# * this purpose. See https://nmap.org/oem/ +# * +# * If you have received a written Nmap license agreement or contract +# * stating terms other than these (such as an Nmap OEM license), you may +# * choose to use and redistribute Nmap under those terms instead. +# * +# * The official Nmap Windows builds include the Npcap software +# * (https://npcap.com) for packet capture and transmission. It is under +# * separate license terms which forbid redistribution without special +# * permission. So the official Nmap Windows builds may not be redistributed +# * without special permission (such as an Nmap OEM license). +# * +# * Source is provided to this software because we believe users have a +# * right to know exactly what a program is going to do before they run it. +# * This also allows you to audit the software for security holes. +# * +# * Source code also allows you to port Nmap to new platforms, fix bugs, and add +# * new features. You are highly encouraged to submit your changes as a Github PR +# * or by email to the dev@nmap.org mailing list for possible incorporation into +# * the main distribution. Unless you specify otherwise, it is understood that +# * you are offering us very broad rights to use your submissions as described in +# * the Nmap Public Source License Contributor Agreement. This is important +# * because we fund the project by selling licenses with various terms, and also +# * because the inability to relicense code has caused devastating problems for +# * other Free Software projects (such as KDE and NASM). +# * +# * The free version of Nmap 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. Warranties, +# * indemnification and commercial support are all available through the +# * Npcap OEM program--see https://nmap.org/oem/ +# * +# ***************************************************************************/ + +from radialnet.core.Coordinate import CartesianCoordinate +from radialnet.util.geometry import normalize_angle +import math + + +def ipv4_compare(ip1, ip2): + """ + """ + ip1 = [int(i) for i in ip1.split('.')] + ip2 = [int(i) for i in ip2.split('.')] + + for i in range(4): + + if ip1[i] != ip2[i]: + + if ip1[i] < ip2[i]: + return -1 + + else: + return 1 + + return 0 + + +def swap(list, a, b): + """ + """ + list[a], list[b] = list[b], list[a] + + +def sort_children(children, father): + """ + """ + if len(children) < 2: + return children + + # create angle reference + f_x, f_y = father.get_cartesian_coordinate() + + for child in children: + + c_x, c_y = child.get_cartesian_coordinate() + _, angle = CartesianCoordinate(c_x - f_x, c_y - f_y).to_polar() + + child.set_draw_info({'angle_from_father': math.degrees(angle)}) + + return sort_children_by_angle(children) + + +def sort_children_by_angle(children): + """ + """ + + vector = list(children) + vector.sort( + key=lambda c: normalize_angle( + c.get_draw_info('angle_from_father'))) + return vector |