Hello community,

here is the log from the commit of package arpwatch-ethercodes for 
openSUSE:Factory checked in at 2020-11-10 13:46:54
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/arpwatch-ethercodes (Old)
 and      /work/SRC/openSUSE:Factory/.arpwatch-ethercodes.new.11331 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "arpwatch-ethercodes"

Tue Nov 10 13:46:54 2020 rev:765 rq:847429 version:20201026_100149

Changes:
--------
--- /work/SRC/openSUSE:Factory/arpwatch-ethercodes/arpwatch-ethercodes.changes  
2016-04-12 19:34:28.000000000 +0200
+++ 
/work/SRC/openSUSE:Factory/.arpwatch-ethercodes.new.11331/arpwatch-ethercodes.changes
       2020-11-10 13:53:40.538824782 +0100
@@ -1,0 +2,17 @@
+Tue Nov 10 08:42:20 UTC 2020 - Johannes Segitz <jseg...@suse.com>
+
+- Removed URL for source0 as this causes issues with our bots
+
+-------------------------------------------------------------------
+Mon Oct 26 10:14:43 UTC 2020 - Hans-Peter Jansen <h...@urpla.net>
+
+- Update to version 20201026_100149
+
+-------------------------------------------------------------------
+Wed Sep 26 09:51:54 UTC 2018 - Hans-Peter Jansen <h...@urpla.net>
+
+- supply a new python3 script, that fetches (in local builds) and
+  generates ethercodes.dat 
+- update to version 20180926_160344
+
+-------------------------------------------------------------------
@@ -4,0 +22,5 @@
+
+-------------------------------------------------------------------
+Fri Jun 19 12:54:32 UTC 2015 - lmue...@suse.com
+
+- merge oui data base from 2015-06-19

Old:
----
  oui.txt

New:
----
  fetch_ethercodes.py
  oui.csv

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ arpwatch-ethercodes.spec ++++++
--- /var/tmp/diff_new_pack.kV8Pvu/_old  2020-11-10 13:53:41.834822332 +0100
+++ /var/tmp/diff_new_pack.kV8Pvu/_new  2020-11-10 13:53:41.834822332 +0100
@@ -1,7 +1,8 @@
 #
 # spec file for package arpwatch-ethercodes
 #
-# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LLC
+# Copyright (c) 2018 LISA GmbH, Bingen, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -12,43 +13,45 @@
 # license that conforms to the Open Source Definition (Version 1.9)
 # published by the Open Source Initiative.
 
-# Please submit bugfixes or comments via http://bugs.opensuse.org/
+# Please submit bugfixes or comments via https://bugs.opensuse.org/
 #
 
 
 Name:           arpwatch-ethercodes
-Version:        2016.03.28
+Version:        20201026_100149
 Release:        0
 Summary:        Ethercodes Data for arpwatch
 License:        BSD-3-Clause
 Group:          Productivity/Networking/Diagnostic
-Url:            http://standards.ieee.org/regauth/oui/
-Source0:        http://standards.ieee.org/regauth/oui/oui.txt
-BuildRequires:  arpwatch-ethercodes-build
-BuildRoot:      %{_tmppath}/%{name}-%{version}-build
+URL:            https://standards.ieee.org/products-services/regauth/index.html
+# can't use url as it's not stable and bots will decline submission. Update it 
+# from here: http://standards-oui.ieee.org/oui/oui.csv
+Source0:        oui.csv
+Source1:        fetch_ethercodes.py
+BuildRequires:  python3
 BuildArch:      noarch
 
 %description
-OUI and company ID data as fetched from IEEE.org prepared for arpwatch.
+Fetch OUI and company ID data from IEEE.org prepared for arpwatch.
 
 %prep
+%setup -q -cT
+cp -p %{SOURCE0} .
+cp -p %{SOURCE1} .
 
 %build
-pushd %{_datadir}/arpwatch
-./massagevendor >${RPM_BUILD_DIR}/ethercodes.dat < %{SOURCE0}
-popd
-if [ ! -s ethercodes.dat ]; then
-       echo "File ethercodes.dat is empty!"
-       exit 1
-fi
+# update oui.csv by executing
+#  python3 fetch_ethercodes.py -vvtp arpwatch-ethercodes.spec
+# in a local build
+
+# (re)generate ethercodes.dat from oui.csv
+python3 fetch_ethercodes.py -vvkt
 
 %install
-mkdir -p \
-       %{buildroot}/%{_datadir}/arpwatch
-install -m 0444 ethercodes.dat %{buildroot}/%{_datadir}/arpwatch
+install -Dm0444 ethercodes.dat %{buildroot}/%{_datadir}/arpwatch/ethercodes.dat
 
 %files
-%defattr(-,root,root)
-%{_datadir}/arpwatch
+%dir %{_datadir}/arpwatch
+%{_datadir}/arpwatch/ethercodes.dat
 
 %changelog

++++++ fetch_ethercodes.py ++++++
#! /usr/bin/env python3
"""
Synopsis:
Fetch and generate ethercodes data for arpwatch

Usage: {appname} [-hVvfkt][-T sec][-O ouifile][-o outfile][-p spec]
       -h, --help           this message
       -V, --version        print version and exit
       -v, --verbose        verbose mode (cumulative)
       -f, --force          force operation
       -k, --keep           keep existing {ouifile}
       -t, --timestamp      print timestamp
       -T, --deltat sec     tolerance in timestamp comparison
                            (default: {deltat} sec.)
       -O, --ouifile file   IEEE.org host
                            (default: {ouifile})
       -o, --outfile file   arpwatch ethercodes
                            (default: {outfile})
       -p, --patch spec     patch specfile with updated timestamp

Description:
Fetch current IEEE MA-L Assignments file (oui.csv) from IEEE.org,
and generate ethercodes.dat for arpwatch consumption.

Fetch oui.csv only, if the timestamp is newer (unless --force is given).
Similar, generate ethercodes.dat only, if the timestamps don't match
(again, unless --force is given). Use option --keep to (re)generate
ethercodes.dat from an existing oui.csv.

Patch replaces a pattern NNNNNNNN_NNNNNN with the current timestamp
in the given file.

Notes:
The timestamps of oui.csv fluctuate in a 2 seconds range(!). Therefore
compensate the fluctuation by taking a deltat tolerance factor into
account.

Copyright:
(c)2018 by {author} {email}

License:
{license}
"""
#
# vim:set et ts=8 sw=4:
#

__version__ = '0.3'
__author__ = 'Hans-Peter Jansen'
__email__ = '<h...@urpla.net>'
__license__ = 'MIT'


import os
import re
import csv
import sys
import time
import getopt
import traceback
import email.utils
import urllib.error
import urllib.parse
import urllib.request

# avoid encoding issues with print() in locale-less environments
os.environ["PYTHONIOENCODING"] = "utf-8"

class gpar:
    """ global parameter class """
    appdir, appname = os.path.split(sys.argv[0])
    if appdir == '.':
        appdir = os.getcwd()
    pid = os.getpid()
    version = __version__
    author = __author__
    email = __email__
    license = __license__
    loglevel = 0
    force = False
    keep = False
    timestamp = False
    deltat = 2.5
    ouifile = 'http://standards-oui.ieee.org/oui/oui.csv'
    outfile = 'ethercodes.dat'
    patchfile = None


def vout(lvl, msg):
    if lvl <= gpar.loglevel:
        print((msg).format(**gpar.__dict__), file = sys.stdout, flush = True)

stderr = lambda *msg: print(*msg, file = sys.stderr, flush = True)

def exit(ret = 0, msg = None, usage = False):
    """ terminate process with optional message and usage """
    if msg:
        stderr('{}: {}'.format(gpar.appname, msg))
    if usage:
        stderr(__doc__.format(**gpar.__dict__))
    sys.exit(ret)


def cmp_ts(t1, t2):
    """ compare timestamps while taking a global tolerance factor into
        account
        return True, if timestamps match
    """
    return abs(t1 - t2) < gpar.deltat


hex = lambda x: int(x, 16)
hexstr = lambda h: format(h, 'x')

def code_key(val):
    """ return the colon formated code key, if val is an exact 24 byte
        hexadecimal string, and None otherwise
        000000 -> 0:0:0
        ABCDEF -> ab:cd:ef
    """
    if len(val) == 6:
        return ':'.join((map(hexstr, map(hex, (val[:2], val[2:4], val[4:])))))


def fetch_infile(infile):
    # check oui.csv parameter
    vout(1, 'check {ouifile}')
    req = urllib.request.urlopen(gpar.ouifile)
    vout(3, 'header info: {}'.format(req.info()))
    header = req.info()
    ouisize = int(header['Content-Length'])
    vout(1, 'oui file size: {}'.format(ouisize))
    ouidate = header['Last-Modified']
    vout(1, 'oui file date: {}'.format(ouidate))
    ouidate = email.utils.parsedate(ouidate)
    ouitime = time.mktime(ouidate)
    vout(3, 'parsed oui file date: {} ({})'.format(
            time.asctime(ouidate), ouitime))

    # check, if local oui.csv is outdated
    fetchoui = False
    if gpar.force:
        fetchoui = True
    elif not os.path.exists(infile):
        vout(1, 'no local file {infile} found')
        fetchoui = True
    elif os.path.getsize(infile) != ouisize:
        vout(1, 'local file size differs: {} vs. {} remote'.format(
                os.path.getsize(infile), ouisize))
        fetchoui = True
    elif not cmp_ts(os.stat(infile).st_mtime, ouitime):
        vout(3, str(os.stat(infile).st_mtime))
        vout(3, str(ouitime))
        mtime = time.localtime(os.stat(infile).st_mtime)
        otime = time.localtime(ouitime)
        vout(1, 'local file date differs: {} vs. {} remote'.format(
                time.asctime(mtime), time.asctime(otime)))
        fetchoui = True
    # fetch oui.csv
    if fetchoui:
        vout(1, 'fetch {ouifile}')
        open(infile, 'wb').write(req.read())
        os.utime(infile, (ouitime, ouitime))

    return ouidate


def parse_csv(infile):
    vout(1, 'parse {infile}')
    codes = {}
    with open(infile, newline = '', encoding = 'utf-8') as f:
        reader = csv.reader(f)
        for row in reader:
            vout(3, str(row))
            # generate
            code = code_key(row[1])
            if code:
                if code in codes and codes[code] != row[2]:
                    vout(1, 'value {} exists already: "{}", "{}"'.format(
                            code, codes[code], row[2]))
                else:
                    codes[code] = row[2]
    return codes


def patch_file(patchfile, timestamp):
    vout(1, 'patch {}'.format(patchfile))
    with open(patchfile, 'r+', encoding = 'utf-8') as f:
        content = f.read()
        patched, count = re.subn('\d{8}_\d{6}', timestamp, content)
        if count and content != patched:
            f.seek(0)
            f.write(patched)
            vout(1, '{} occurances replaced in {}'.format(count, patchfile))
        else:
            vout(1, '{} unchanged'.format(patchfile))


def fetch_ethercodes():
    # extract file argument from URL
    gpar.infile = os.path.basename(urllib.parse.urlparse(gpar.ouifile).path)
    # default: oui.csv
    infile = gpar.infile
    # default: ethercodes.dat
    outfile = gpar.outfile
    if gpar.keep:
        if os.path.exists(infile):
            # force generation of ethercodes.dat from existing oui.csv
            gpar.force = True
            ouidate = time.localtime(os.stat(infile).st_mtime)
        else:
            exit(1, 'keep option selected, but no {infile}')
    else:
        ouidate = fetch_infile(infile)
    ouitime = time.mktime(ouidate)

    # check, if ethercodes.dat is outdated
    gencodes = False
    if gpar.force:
        gencodes = True
    elif not os.path.exists(outfile):
        vout(1, 'no local file {} found'.format(outfile))
        gencodes = True
    elif not cmp_ts(os.stat(outfile).st_mtime, ouitime):
        vout(3, str(os.stat(outfile).st_mtime))
        vout(3, str(ouitime))
        mtime = time.localtime(os.stat(outfile).st_mtime)
        otime = time.localtime(ouitime)
        vout(2, 'local file date differs: {} vs. {} remote'.format(
                time.asctime(mtime), time.asctime(otime)))
        gencodes = True

    # generate ethercodes.dat
    if gencodes:
        codes = parse_csv(infile)
        gpar.nrcodes = len(codes)
        vout(1, 'generate {outfile} with {nrcodes} entries')
        with open(outfile, 'w', newline = '', encoding = 'utf-8') as f:
            for key in sorted(codes.keys()):
                f.write('%s\t%s\n' % (key, codes[key]))
        os.utime(outfile, (ouitime, ouitime))
        vout(1, 'successful')
    else:
        vout(1, 'code file {outfile} up to date already')

    timestamp = time.strftime('%Y%m%d_%H%M%S', ouidate)
    if gpar.timestamp:
        vout(0, 'timestamp: {}'.format(timestamp))

    if gpar.patchfile is not None:
        patch_file(gpar.patchfile, timestamp)

    return 0


def main(argv = None):
    if argv is None:
        argv = sys.argv[1:]

    # yeah, oldschool, I know...
    try:
        optlist, args = getopt.getopt(argv, 'hVvfktT:O:o:p:',
            ('help', 'version', 'verbose', 'force', 'keep', 'timestamp',
             'deltat', 'ouifile', 'outfile', 'patch')
        )
    except getopt.error as msg:
        exit(1, msg, True)

    for opt, par in optlist:
        if opt in ('-h', '--help'):
            exit(usage = True)
        elif opt in ('-V', '--version'):
            exit(msg = 'version %s' % gpar.version)
        elif opt in ('-v', '--verbose'):
            gpar.loglevel += 1
        elif opt in ('-f', '--force'):
            gpar.force = True
        elif opt in ('-k', '--keep'):
            gpar.keep = True
        elif opt in ('-t', '--timestamp'):
            gpar.timestamp = True
        elif opt in ('-T', '--deltat'):
            gpar.deltat = par
        elif opt in ('-O', '--ouifile'):
            gpar.ouifile = par
        elif opt in ('-o', '--outfile'):
            gpar.outfile = par
        elif opt in ('-p', '--patch'):
            gpar.patchfile = par

    try:
        fetch_ethercodes()
    except Exception:
        exit(2, 'unexpected exception occured:\n%s' % traceback.format_exc())


if __name__ == '__main__':
    sys.exit(main())
++++++ oui.csv ++++++
++++ 28784 lines (skipped)


Reply via email to