Accepting request 1233388 from security
OBS-URL: https://build.opensuse.org/request/show/1233388 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/arpwatch-ethercodes?expand=0&rev=774
This commit is contained in:
commit
aa5215b7d7
@ -1,7 +1,87 @@
|
||||
-------------------------------------------------------------------
|
||||
Fri Jun 29 08:40:05 CEST 2012 - autobuild@suse.de
|
||||
Thu Dec 12 12:12:12 UTC 2024 - olaf@aepfle.de
|
||||
|
||||
- automated update on 2012-06-29
|
||||
- Update to version 20241212
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Thu Aug 8 08:08:08 UTC 2024 - olaf@aepfle.de
|
||||
|
||||
- Update to version 20240808
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Thu Apr 4 04:04:04 UTC 2024 - olaf@aepfle.de
|
||||
|
||||
- Update to version 20240404
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Tue Dec 12 12:12:12 UTC 2023 - olaf@aepfle.de
|
||||
|
||||
- Update to version 20231212
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Tue Aug 8 08:08:08 UTC 2023 - olaf@aepfle.de
|
||||
|
||||
- Update to version 20230808
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Thu Apr 20 20:20:20 UTC 2023 - olaf@aepfle.de
|
||||
|
||||
- Update to version 20230420
|
||||
- Inject a QEMU/KVM entry
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Thu Feb 9 09:09:09 UTC 2023 - olaf@aepfle.de
|
||||
|
||||
- Update to version 20230209
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Mon Dec 12 12:12:12 UTC 2022 - olaf@aepfle.de
|
||||
|
||||
- Update to version 20221212
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Fri Nov 11 11:11:11 UTC 2022 - olaf@aepfle.de
|
||||
|
||||
- sort existing oui.csv to show differences in future updates
|
||||
- sort downloaded oui.csv
|
||||
- move vim commands to a place where vim can find the commands
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Tue Nov 10 08:42:20 UTC 2020 - Johannes Segitz <jsegitz@suse.com>
|
||||
|
||||
- Removed URL for source0 as this causes issues with our bots
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Mon Oct 26 10:14:43 UTC 2020 - Hans-Peter Jansen <hpj@urpla.net>
|
||||
|
||||
- Update to version 20201026_100149
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Wed Sep 26 09:51:54 UTC 2018 - Hans-Peter Jansen <hpj@urpla.net>
|
||||
|
||||
- supply a new python3 script, that fetches (in local builds) and
|
||||
generates ethercodes.dat
|
||||
- update to version 20180926_160344
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Sun Mar 27 22:12:59 UTC 2016 - mpluskal@suse.com
|
||||
|
||||
- Update to 2016-03-28
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Fri Jun 19 12:54:32 UTC 2015 - lmuelle@suse.com
|
||||
|
||||
- merge oui data base from 2015-06-19
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Wed Jul 2 12:51:38 UTC 2014 - coolo@suse.com
|
||||
|
||||
- manual update on 2014-07-02
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Sun Feb 10 11:43:02 CET 2013 - autobuild@suse.de
|
||||
|
||||
- automated update on 2013-02-10
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Tue Sep 20 07:40:05 CEST 2011 - autobuild@suse.de
|
||||
|
@ -1,7 +1,8 @@
|
||||
#
|
||||
# spec file for package arpwatch-ethercodes
|
||||
#
|
||||
# Copyright (c) 2011 SUSE LINUX Products GmbH, Nuernberg, Germany.
|
||||
# Copyright (c) 2024 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,44 +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
|
||||
BuildRequires: arpwatch-ethercodes-build
|
||||
Url: http://standards.ieee.org/regauth/oui/
|
||||
Version: 20241212
|
||||
Release: 0
|
||||
Summary: Ethercodes Data for arpwatch
|
||||
License: BSD-3-Clause
|
||||
Group: Productivity/Networking/Diagnostic
|
||||
Summary: Ethercodes Data for arpwatch
|
||||
Version: 2012.6.29
|
||||
Release: 1
|
||||
Source0: http://standards.ieee.org/regauth/oui/oui.txt
|
||||
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 /usr/share/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 \
|
||||
$RPM_BUILD_ROOT/%{_datadir}/arpwatch
|
||||
install -m 0444 ethercodes.dat $RPM_BUILD_ROOT/%{_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
|
||||
|
328
fetch_ethercodes.py
Normal file
328
fetch_ethercodes.py
Normal file
@ -0,0 +1,328 @@
|
||||
#! /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}
|
||||
"""
|
||||
#
|
||||
#
|
||||
|
||||
__version__ = '0.3'
|
||||
__author__ = 'Hans-Peter Jansen'
|
||||
__email__ = '<hpj@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 append_qemu(content):
|
||||
content += b'MA-L,525400,QEMU/KVM,Cyberspace\x0d\x0a'
|
||||
return content
|
||||
|
||||
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}')
|
||||
content = req.read()
|
||||
content = append_qemu(content)
|
||||
lines = content.split(sep=b'\r')
|
||||
heading = lines.pop(0).replace(b'\n', b'', 1)
|
||||
|
||||
sort_dict = {}
|
||||
for line in lines:
|
||||
stripped = line.replace(b'\n', b'', 1)
|
||||
items = stripped.split(b',', 3)
|
||||
if len(stripped) == 0:
|
||||
continue
|
||||
OUI = items[1].decode('ascii').lower()
|
||||
if OUI in sort_dict:
|
||||
sort_dict[OUI].append(stripped)
|
||||
else:
|
||||
sort_dict[OUI] = [stripped]
|
||||
|
||||
with open(infile, 'wb') as f:
|
||||
CRLF = b'\r\n'
|
||||
f.write(heading)
|
||||
f.write(CRLF)
|
||||
for OUI in sorted(sort_dict.keys()):
|
||||
items = sort_dict[OUI]
|
||||
for item in items:
|
||||
f.write(item)
|
||||
f.write(CRLF)
|
||||
|
||||
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}', 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', 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())
|
||||
# vim: ts=8 shiftwidth=8 expandtab
|
@ -1 +0,0 @@
|
||||
get_date_version_string $( find_newest_file oui.txt)
|
Loading…
Reference in New Issue
Block a user