From 2a54fe68cadcb2b75c9c31244499c2b21f385eb4 Mon Sep 17 00:00:00 2001
From: gpotter2 <gpotter2@users.noreply.github.com>
Date: Sat, 18 Feb 2017 15:59:50 +0000
Subject: [PATCH] [Logs] Several logs fixes: interractive + pyx + duplication
 (#485)

* Better warning()

* Tiny import fix

* Several log fixes

* Added docstrings

* Fixed imports
---
 scapy/arch/bpf/core.py                 |  3 +--
 scapy/arch/bpf/supersocket.py          |  3 +--
 scapy/arch/pcapdnet.py                 |  4 ++--
 scapy/arch/windows/__init__.py         | 12 ++++++------
 scapy/arch/windows/disable_sendrecv.py | 10 ++++++++--
 scapy/config.py                        |  1 +
 scapy/consts.py                        | 21 +++++++++++++++++++--
 scapy/contrib/coap.py                  |  1 +
 scapy/contrib/gtp.py                   |  1 +
 scapy/contrib/icmp_extensions.py       |  2 +-
 scapy/contrib/ppi_geotag.py            |  1 +
 scapy/error.py                         | 26 +++++++++++++-------------
 scapy/fields.py                        |  1 +
 scapy/layers/dhcp.py                   |  1 +
 scapy/layers/dhcp6.py                  |  1 +
 scapy/layers/dns.py                    |  1 +
 scapy/layers/dot11.py                  |  1 +
 scapy/layers/isakmp.py                 |  1 +
 scapy/layers/l2.py                     |  1 +
 scapy/main.py                          |  3 ++-
 scapy/packet.py                        |  5 ++++-
 scapy/pipetool.py                      |  4 ++--
 scapy/route.py                         |  4 ++--
 scapy/sendrecv.py                      |  4 ++--
 scapy/utils.py                         |  6 +-----
 scapy/utils6.py                        |  1 +
 26 files changed, 76 insertions(+), 43 deletions(-)

diff --git a/scapy/arch/bpf/core.py b/scapy/arch/bpf/core.py
index 5d84f233..c02b744e 100644
--- a/scapy/arch/bpf/core.py
+++ b/scapy/arch/bpf/core.py
@@ -5,11 +5,10 @@ Scapy *BSD native support - core
 """
 
 from scapy.config import conf
-from scapy.error import Scapy_Exception
+from scapy.error import Scapy_Exception, warning
 from scapy.data import ARPHDR_LOOPBACK, ARPHDR_ETHER
 from scapy.arch.common import get_if
 from scapy.consts import LOOPBACK_NAME
-from scapy.utils import warning
 
 from scapy.arch.bpf.consts import *
 
diff --git a/scapy/arch/bpf/supersocket.py b/scapy/arch/bpf/supersocket.py
index 244e909c..5d03c1bd 100644
--- a/scapy/arch/bpf/supersocket.py
+++ b/scapy/arch/bpf/supersocket.py
@@ -5,7 +5,7 @@ Scapy *BSD native support - BPF sockets
 """
 
 from scapy.config import conf
-from scapy.error import Scapy_Exception
+from scapy.error import Scapy_Exception, warning
 from scapy.supersocket import SuperSocket
 from scapy.layers.l2 import Ether
 from scapy.layers.inet import IP
@@ -13,7 +13,6 @@ from scapy.layers.inet6 import IPv6
 from scapy.packet import Raw
 from scapy.data import ETH_P_ALL
 from scapy.consts import FREEBSD, OPENBSD, NETBSD
-from scapy.utils import warning
 
 from scapy.arch.bpf.core import get_dev_bpf, attach_filter
 from scapy.arch.bpf.consts import *
diff --git a/scapy/arch/pcapdnet.py b/scapy/arch/pcapdnet.py
index f90fdacb..a5a1e273 100644
--- a/scapy/arch/pcapdnet.py
+++ b/scapy/arch/pcapdnet.py
@@ -14,9 +14,9 @@ if not sys.platform.startswith("win"):
 
 from scapy.data import *
 from scapy.config import conf
-from scapy.utils import warning, mac2str
+from scapy.utils import mac2str
 from scapy.supersocket import SuperSocket
-from scapy.error import Scapy_Exception, log_loading
+from scapy.error import Scapy_Exception, log_loading, warning
 import scapy.arch
 
 if conf.use_winpcapy:
diff --git a/scapy/arch/windows/__init__.py b/scapy/arch/windows/__init__.py
index 07115f33..b1ca9637 100755
--- a/scapy/arch/windows/__init__.py
+++ b/scapy/arch/windows/__init__.py
@@ -11,8 +11,8 @@ import subprocess as sp
 from glob import glob
 import tempfile
 
-from scapy.config import conf,ConfClass
-from scapy.error import Scapy_Exception,log_loading,log_runtime
+from scapy.config import conf, ConfClass
+from scapy.error import Scapy_Exception, log_loading, log_runtime, warning
 from scapy.utils import atol, itom, inet_aton, inet_ntoa, PcapReader
 from scapy.base_classes import Gen, Net, SetGen
 from scapy.data import MTU, ETHER_BROADCAST, ETH_P_ARP
@@ -312,10 +312,10 @@ class NetworkInterfaceDict(UserDict):
                 pass
         
         if len(self.data) == 0 and conf.use_winpcapy:
-            log_loading.warning("No match between your pcap and windows network interfaces found. "
+            warning("No match between your pcap and windows network interfaces found. "
                                 "You probably won't be able to send packets. "
                                 "Deactivating unneeded interfaces and restarting Scapy might help."
-                                "Check your winpcap and powershell installation, and access rights.")
+                                "Check your winpcap and powershell installation, and access rights.", True)
 
     def dev_from_name(self, name):
         """Return the first pcap device name for a given Windows
@@ -440,10 +440,10 @@ def read_routes():
         else:
             routes = read_routes_7()
     except Exception as e:    
-        log_loading.warning("Error building scapy routing table : %s" % str(e))
+        warning("Error building scapy routing table : %s" % str(e), True)
     else:
         if not routes:
-            log_loading.warning("No default IPv4 routes found. Your Windows release may no be supported and you have to enter your routes manually")
+            warning("No default IPv4 routes found. Your Windows release may no be supported and you have to enter your routes manually", True)
     return routes
        
 def read_routes_post2008():
diff --git a/scapy/arch/windows/disable_sendrecv.py b/scapy/arch/windows/disable_sendrecv.py
index ab78af0e..e9d514c6 100644
--- a/scapy/arch/windows/disable_sendrecv.py
+++ b/scapy/arch/windows/disable_sendrecv.py
@@ -12,14 +12,20 @@ import scapy.sendrecv as sendrecv
 import scapy.config as conf
 from scapy.supersocket import SuperSocket
 
+def log_warning():
+    if conf.conf.interactive:
+        log_runtime.warning("Function not available (winpcap is not installed)")
+    else:
+        raise ImportError("Function not available (winpcap is not installed)")
+
 def not_available(*args, **kwargs):
-    log_runtime.warning("Function not available")
+    log_warning()
     return None
 
 class not_available_socket(SuperSocket):
     desc = "wpcap.dll missing"
     def __init__(self, type=None, promisc=None, filter=None, iface=None, nofilter=0):
-        log_runtime.warning("Function not available")
+        log_warning()
         return
     def send(self, x):
         return
diff --git a/scapy/config.py b/scapy/config.py
index e46ffead..b858065e 100755
--- a/scapy/config.py
+++ b/scapy/config.py
@@ -382,6 +382,7 @@ debug_tls:When 1, print some TLS session secrets when they are computed.
     debug_dissector = 0
     color_theme = Interceptor("color_theme", themes.NoTheme(), _prompt_changer)
     warning_threshold = 5
+    warning_next_only_once = False
     prog = ProgPath()
     resolve = Resolve()
     noenum = Resolve()
diff --git a/scapy/consts.py b/scapy/consts.py
index 12b80098..cb498333 100644
--- a/scapy/consts.py
+++ b/scapy/consts.py
@@ -8,6 +8,8 @@ from sys import platform, maxsize
 import platform as platform_lib
 from scapy.error import *
 
+import subprocess
+
 try:
     from matplotlib import get_backend as matplotlib_get_backend
     import matplotlib.pyplot as plt
@@ -25,12 +27,27 @@ except (ImportError, RuntimeError):
     MATPLOTLIB_DEFAULT_PLOT_KARGS = dict()
     log_loading.info("Can't import matplotlib. Won't be able to plot.")
 
+def test_pyx():
+    """Returns if PyX is correctly installed or not"""
+    try:
+        with open(os.devnull, 'wb') as devnull:
+            r = subprocess.check_call(["pdflatex", "--version"], stdout=devnull, stderr=subprocess.STDOUT)
+    except:
+        return False
+    else:
+        return r == 0
+
 try:
     import pyx
-    PYX=1
+    if test_pyx():
+        PYX = 1
+    else:
+        log_loading.warning("PyX dependencies are not installed ! Please install TexLive or MikTeX.")
+        PYX = 0
 except ImportError:
     log_loading.info("Can't import PyX. Won't be able to use psdump() or pdfdump().")
-    PYX=0
+    PYX = 0
+
 
 LINUX = platform.startswith("linux")
 OPENBSD = platform.startswith("openbsd")
diff --git a/scapy/contrib/coap.py b/scapy/contrib/coap.py
index fcadb6c9..9c8bf65a 100644
--- a/scapy/contrib/coap.py
+++ b/scapy/contrib/coap.py
@@ -23,6 +23,7 @@ RFC 7252 - Constrained Application Protocol (CoAP) layer for Scapy
 from scapy.fields import *
 from scapy.layers.inet import UDP
 from scapy.packet import *
+from scapy.error import warning
 
 coap_codes = {
     0: "Empty",
diff --git a/scapy/contrib/gtp.py b/scapy/contrib/gtp.py
index 455c6f09..4fef6c02 100644
--- a/scapy/contrib/gtp.py
+++ b/scapy/contrib/gtp.py
@@ -17,6 +17,7 @@ from scapy.packet import *
 from scapy.fields import *
 from scapy.layers.inet import IP, UDP
 from scapy.layers.inet6 import IP6Field
+from scapy.error import warning
 
 # GTP Data types
 
diff --git a/scapy/contrib/icmp_extensions.py b/scapy/contrib/icmp_extensions.py
index 56820898..3dcaf8d2 100644
--- a/scapy/contrib/icmp_extensions.py
+++ b/scapy/contrib/icmp_extensions.py
@@ -3,7 +3,7 @@ from scapy.packet import Packet, bind_layers
 from scapy.fields import *
 from scapy.layers.inet import IP, ICMP
 from scapy.layers.inet6 import IP6Field
-from scapy.utils import warning
+from scapy.error import warning
 from scapy.contrib.mpls import MPLS
 
 
diff --git a/scapy/contrib/ppi_geotag.py b/scapy/contrib/ppi_geotag.py
index 5863db38..9155653b 100644
--- a/scapy/contrib/ppi_geotag.py
+++ b/scapy/contrib/ppi_geotag.py
@@ -14,6 +14,7 @@ import struct, time
 from scapy.packet import *
 from scapy.fields import *
 from scapy.contrib.ppi import PPIGenericFldHdr,addPPIType
+from scapy.error import warning
 
 # On windows, epoch is 01/02/1970 at 00:00
 EPOCH = time.mktime((1970, 1, 2, 0, 0, 0, 0, 0, 0))-86400
diff --git a/scapy/error.py b/scapy/error.py
index b2a3b4f8..793e220b 100644
--- a/scapy/error.py
+++ b/scapy/error.py
@@ -14,13 +14,13 @@ Logging subsystem and basic exception class.
 class Scapy_Exception(Exception):
     pass
 
-import logging,traceback,time
+import logging, traceback, time
 
 class ScapyFreqFilter(logging.Filter):
     def __init__(self):
         logging.Filter.__init__(self)
         self.warning_table = {}
-    def filter(self, record):        
+    def filter(self, record):
         from scapy.config import conf
         wt = conf.warning_threshold
         if wt > 0:
@@ -36,6 +36,9 @@ class ScapyFreqFilter(logging.Filter):
                 tm = ltm
                 nb = 0
             else:
+                if conf.warning_next_only_once:
+                    conf.warning_next_only_once = False
+                    return 0
                 if nb < 2:
                     nb += 1
                     if nb == 2:
@@ -60,18 +63,15 @@ log_runtime.addFilter(ScapyFreqFilter())
 log_interactive = logging.getLogger("scapy.interactive")  # logs in interactive functions
 log_loading = logging.getLogger("scapy.loading")          # logs when loading Scapy
 
-def muteLogLoading(mute):
-    """
-        This mutes the log loading: used when a class is loaded several times,
-        to avoid the warning messages to be showed more than once.
-        :param mute: setting it to True will mute, False will un-mute
-    """
-    if not mute:
-        log_loading.setLevel(logging.WARNING)
-    else:
-        log_loading.setLevel(logging.CRITICAL)
 
+def warning(x, onlyOnce=None):
+    """
+    Prints a warning during runtime.
 
-def warning(x):
+    onlyOnce - if True, the warning will never be printed again.
+    """ 
+    if onlyOnce:
+        from scapy.config import conf
+        conf.warning_next_only_once = True
     log_runtime.warning(x)
 
diff --git a/scapy/fields.py b/scapy/fields.py
index 8ec15ef9..7f49f2cc 100644
--- a/scapy/fields.py
+++ b/scapy/fields.py
@@ -13,6 +13,7 @@ from scapy.volatile import *
 from scapy.data import *
 from scapy.utils import *
 from scapy.base_classes import BasePacket, Gen, Net, Field_metaclass
+from scapy.error import warning
 
 
 ############
diff --git a/scapy/layers/dhcp.py b/scapy/layers/dhcp.py
index 3b4b5526..139bb320 100644
--- a/scapy/layers/dhcp.py
+++ b/scapy/layers/dhcp.py
@@ -21,6 +21,7 @@ from scapy.volatile import RandField
 
 from scapy.arch import get_if_raw_hwaddr
 from scapy.sendrecv import *
+from scapy.error import warning
 
 dhcpmagic="c\x82Sc"
 
diff --git a/scapy/layers/dhcp6.py b/scapy/layers/dhcp6.py
index 7980a51c..19715c06 100644
--- a/scapy/layers/dhcp6.py
+++ b/scapy/layers/dhcp6.py
@@ -20,6 +20,7 @@ from scapy.themes import Color
 from scapy.layers.inet6 import *
 from scapy.ansmachine import AnsweringMachine
 from scapy.sendrecv import *
+from scapy.error import warning
 
 #############################################################################
 # Helpers                                                                  ##
diff --git a/scapy/layers/dns.py b/scapy/layers/dns.py
index e1774967..ccbefcce 100644
--- a/scapy/layers/dns.py
+++ b/scapy/layers/dns.py
@@ -16,6 +16,7 @@ from scapy.ansmachine import *
 from scapy.sendrecv import sr1
 from scapy.layers.inet import IP, DestIPField, UDP, TCP
 from scapy.layers.inet6 import DestIP6Field
+from scapy.error import warning
 
 class DNSStrField(StrField):
 
diff --git a/scapy/layers/dot11.py b/scapy/layers/dot11.py
index 8474412e..c8e4f972 100644
--- a/scapy/layers/dot11.py
+++ b/scapy/layers/dot11.py
@@ -18,6 +18,7 @@ from scapy.ansmachine import *
 from scapy.plist import PacketList
 from scapy.layers.l2 import *
 from scapy.layers.inet import IP, TCP
+from scapy.error import warning
 
 
 if conf.crypto_valid:
diff --git a/scapy/layers/isakmp.py b/scapy/layers/isakmp.py
index 17e538dd..90c703c9 100644
--- a/scapy/layers/isakmp.py
+++ b/scapy/layers/isakmp.py
@@ -14,6 +14,7 @@ from scapy.fields import *
 from scapy.ansmachine import *
 from scapy.layers.inet import IP,UDP
 from scapy.sendrecv import sr
+from scapy.error import warning
 
 
 # see http://www.iana.org/assignments/ipsec-registry for details
diff --git a/scapy/layers/l2.py b/scapy/layers/l2.py
index e81c4e7b..ca87d469 100644
--- a/scapy/layers/l2.py
+++ b/scapy/layers/l2.py
@@ -20,6 +20,7 @@ from scapy.sendrecv import srp, srp1, srpflood
 from scapy.arch import get_if_hwaddr
 from scapy.consts import LOOPBACK_NAME
 from scapy.utils import inet_ntoa, inet_aton
+from scapy.error import warning
 if conf.route is None:
     # unused import, only to initialize conf.route
     import scapy.route
diff --git a/scapy/main.py b/scapy/main.py
index 3e468868..ef99e6db 100644
--- a/scapy/main.py
+++ b/scapy/main.py
@@ -15,7 +15,6 @@ import cPickle
 import __builtin__
 
 from scapy.error import *
-from scapy import utils
     
 
 def _probe_config_file(cf):
@@ -120,6 +119,7 @@ def list_contrib(name=None):
 
 
 def save_session(fname=None, session=None, pickleProto=-1):
+    from scapy import utils
     if fname is None:
         fname = conf.session
         if not fname:
@@ -232,6 +232,7 @@ def scapy_delete_temp_files():
             pass
 
 def scapy_write_history_file(readline):
+    from scapy import utils
     if conf.histfile:
         try:
             readline.write_history_file(conf.histfile)
diff --git a/scapy/packet.py b/scapy/packet.py
index d5ff4526..04689acd 100644
--- a/scapy/packet.py
+++ b/scapy/packet.py
@@ -18,7 +18,8 @@ from scapy.config import conf
 from scapy.base_classes import BasePacket, Gen, SetGen, Packet_metaclass
 from scapy.volatile import VolatileValue
 from scapy.utils import import_hexcap,tex_escape,colgen,get_temp_file
-from scapy.error import Scapy_Exception,log_runtime
+from scapy.error import Scapy_Exception, log_runtime
+from scapy.consts import PYX
 
 try:
     import pyx
@@ -422,6 +423,8 @@ Creates an EPS file describing a packet. If filename is not provided a temporary
 
         
     def canvas_dump(self, layer_shift=0, rebuild=1):
+        if PYX == 0:
+            raise ImportError("PyX and its depedencies must be installed")
         canvas = pyx.canvas.canvas()
         if rebuild:
             p,t = self.__class__(str(self)).build_ps()
diff --git a/scapy/pipetool.py b/scapy/pipetool.py
index 7e745887..b50ef01a 100644
--- a/scapy/pipetool.py
+++ b/scapy/pipetool.py
@@ -5,7 +5,7 @@
 ## Copyright (C) Philippe Biondi <phil@secdev.org>
 ## This program is published under a GPLv2 license
 
-import os,thread,select
+import os, thread, select
 import subprocess
 import itertools
 import collections
@@ -13,7 +13,7 @@ import time
 import Queue
 import scapy.utils
 
-from scapy.error import log_interactive,warning
+from scapy.error import log_interactive, warning
 from scapy.config import conf
 
 class PipeEngine:
diff --git a/scapy/route.py b/scapy/route.py
index 14e24473..9c3ad897 100644
--- a/scapy/route.py
+++ b/scapy/route.py
@@ -9,9 +9,9 @@ Routing and handling of network interfaces.
 
 import socket
 from scapy.consts import LOOPBACK_NAME
-from scapy.utils import atol,ltoa,itom
+from scapy.utils import atol, ltoa, itom
 from scapy.config import conf
-from scapy.error import Scapy_Exception,warning
+from scapy.error import Scapy_Exception, warning
 from scapy.arch import WINDOWS
 
 ##############################
diff --git a/scapy/sendrecv.py b/scapy/sendrecv.py
index 71d54355..e5eecbba 100644
--- a/scapy/sendrecv.py
+++ b/scapy/sendrecv.py
@@ -16,9 +16,9 @@ from scapy.consts import DARWIN, FREEBSD, OPENBSD
 from scapy.data import *
 from scapy.config import conf
 from scapy.packet import Gen
-from scapy.utils import warning, get_temp_file, PcapReader, tcpdump, wrpcap
+from scapy.utils import get_temp_file, PcapReader, tcpdump, wrpcap
 from scapy import plist
-from scapy.error import log_runtime,log_interactive
+from scapy.error import log_runtime, log_interactive, warning
 from scapy.base_classes import SetGen
 from scapy.supersocket import StreamSocket
 if conf.route is None:
diff --git a/scapy/utils.py b/scapy/utils.py
index 9d2a56c0..58df161f 100644
--- a/scapy/utils.py
+++ b/scapy/utils.py
@@ -20,7 +20,7 @@ warnings.filterwarnings("ignore","tempnam",RuntimeWarning, __name__)
 from scapy.config import conf
 from scapy.consts import DARWIN, WINDOWS
 from scapy.data import MTU
-from scapy.error import log_runtime,log_loading,log_interactive, Scapy_Exception
+from scapy.error import log_runtime, log_loading, log_interactive, Scapy_Exception, warning
 from scapy.base_classes import BasePacketList
 
 ###########
@@ -338,9 +338,6 @@ def fletcher16_checkbytes(binbuf, offset):
     return chr(x) + chr(y)
 
 
-def warning(x):
-    log_runtime.warning(x)
-
 def mac2str(mac):
     return "".join(map(lambda x: chr(int(x,16)), mac.split(":")))
 
@@ -394,7 +391,6 @@ try:
     inet_pton = socket.inet_pton
 except AttributeError:
     from scapy.pton_ntop import *
-    log_loading.info("inet_ntop/pton functions not found. Python IPv6 support not present")
 
 
 def atol(x):
diff --git a/scapy/utils6.py b/scapy/utils6.py
index 30ee6ba5..3203e13c 100644
--- a/scapy/utils6.py
+++ b/scapy/utils6.py
@@ -18,6 +18,7 @@ from scapy.data import *
 from scapy.utils import *
 from scapy.pton_ntop import *
 from scapy.volatile import RandMAC
+from scapy.error import warning
 
 
 def construct_source_candidate_set(addr, plen, laddr, loname):
-- 
GitLab