Add my pre-commit git script (with checkAPI/hf/encoding args...) Need to copy in...
[metze/wireshark/wip.git] / tools / make-services.py
1 #!/usr/bin/env python
2 #
3 # Parses the CSV version of the IANA Service Name and Transport Protocol Port Number Registry
4 # and generates a services(5) file.
5 #
6 # Wireshark - Network traffic analyzer
7 # By Gerald Combs <gerald@wireshark.org>
8 # Copyright 2013 Gerald Combs
9 #
10 # This program is free software; you can redistribute it and/or
11 # modify it under the terms of the GNU General Public License
12 # as published by the Free Software Foundation; either version 2
13 # of the License, or (at your option) any later version.
14 #
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 # GNU General Public License for more details.
19 #
20 # You should have received a copy of the GNU General Public License
21 # along with this program; if not, write to the Free Software
22 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23
24 iana_svc_url = 'http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.csv'
25
26 __doc__ = '''\
27 Usage: make-services.py [url]
28
29 url defaults to
30     %s
31 ''' % (iana_svc_url)
32
33 import sys
34 import getopt
35 import csv
36 import re
37
38 python_version = sys.hexversion >> 16
39 if python_version < 0x300:
40     import urllib
41 else:
42     import urllib.request, urllib.error, urllib.parse
43     import codecs
44
45 services_file = 'services'
46
47 exclude_services = [
48     '^spr-itunes',
49     '^spl-itunes',
50     '^shilp',
51     ]
52
53 exclude_comments = [
54     'should not be used for discovery purposes',
55     'NOTE Conflict',
56 ]
57
58 min_body_size = 900000 # Size was ~ 922000 on 2013-08-06
59
60 def parse_rows(svc_fd):
61     lines = []
62     port_reader = csv.reader(svc_fd)
63
64     # Header positions as of 2013-08-06
65     if python_version < 0x206:
66         headers = port_reader.next()
67     else:
68         headers = next(port_reader)
69
70     try:
71         sn_pos = headers.index('Service Name')
72     except:
73         sn_pos = 0
74     try:
75         pn_pos = headers.index('Port Number')
76     except:
77         pn_pos = 1
78     try:
79         tp_pos = headers.index('Transport Protocol')
80     except:
81         tp_pos = 2
82
83     positions = [sn_pos, pn_pos, tp_pos]
84     positions.sort()
85     positions.reverse()
86
87     for row in port_reader:
88         service = row[sn_pos]
89         port = row[pn_pos]
90         proto = row[tp_pos]
91         
92         if len(service) < 1 or len(port) < 1 or len(proto) < 1:
93             continue
94             
95         for pos in positions:
96             del row[pos]
97         row = filter(None, row)
98         comment = ' '.join(row)
99         comment = re.sub('[\n]', '', comment)
100         
101         if re.search('|'.join(exclude_services), service):
102             continue
103         if re.search('|'.join(exclude_comments), comment):
104             continue
105
106         lines.append('%-15s %5s/%s # %s' % (
107             service,
108             port,
109             proto,
110             comment
111         ))
112
113     return '\n'.join(lines)
114
115 def exit_msg(msg=None, status=1):
116     if msg is not None:
117         sys.stderr.write(msg + '\n\n')
118     sys.stderr.write(__doc__ + '\n')
119     sys.exit(status)
120
121 def main(argv):
122     try:
123         opts, args = getopt.getopt(argv, "h", ["help"])
124     except getopt.GetoptError:
125         exit_msg()
126     for opt, arg in opts:
127         if opt in ("-h", "--help"):
128             exit_msg(None, 0)
129
130     if (len(argv) > 0):
131         svc_url = argv[0]
132     else:
133         svc_url = iana_svc_url
134
135     try:
136         if python_version < 0x300:
137             svc_fd = urllib.urlopen(svc_url)
138         else:
139             req = urllib.request.urlopen(svc_url)
140             svc_fd = codecs.getreader('utf8')(req)
141     except:
142         exit_msg('Error opening ' + svc_url)
143
144     body = parse_rows(svc_fd)
145     if len(body) < min_body_size:
146         exit_msg('Not enough parsed data')
147
148     out = open(services_file, 'w')
149     out.write('''\
150 # This is a local copy of the IANA port-numbers file.
151 #
152 # $Id$
153 #
154 # Wireshark uses it to resolve port numbers into human readable
155 # service names, e.g. TCP port 80 -> http.
156 #
157 # It is subject to copyright and being used with IANA's permission:
158 # http://www.wireshark.org/lists/wireshark-dev/200708/msg00160.html
159 #
160 # The original file can be found at:
161 # %s
162 #
163
164 %s
165 ''' % (iana_svc_url, body))
166
167 if __name__ == "__main__":
168     sys.exit(main(sys.argv[1:]))