~ubuntu-branches/ubuntu/trusty/ufw/trusty-proposed

« back to all changes in this revision

Viewing changes to src/util.py

  • Committer: Package Import Robot
  • Author(s): Jamie Strandboge
  • Date: 2012-04-04 12:12:25 UTC
  • mfrom: (30.1.13)
  • mto: This revision was merged to the branch mainline in revision 65.
  • Revision ID: package-import@ubuntu.com-20120404121225-pjt6j7hm3ua0q580
Tags: 0.31.1-1
* New upstream release (Closes: 663677, Closes: 625681)
* debian/control: update to standards 3.9.3
* convert to source format 3.0 (quilt)
* 0001-optimize-boot.patch: only read in /etc/ufw/ufw.conf when disabled
* debian/rules: adjust to only install the application profiles when not
  Ubuntu
* debian/po/nl.po: add Dutch translation of debconf templates. Thanks to
  Jeroen Schot (Closes: 658495)
* debian/po/da.po: add Danish translation of debconf templates. Thanks to
  Joe Dalton (Closes: 666557)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#
2
 
# util.py: utility functions for ufw
 
1
'''util.py: utility functions for ufw'''
3
2
#
4
3
# Copyright 2008-2011 Canonical Ltd.
5
4
#
28
27
 
29
28
from tempfile import mkstemp
30
29
 
31
 
debugging = False
 
30
DEBUGGING = False
32
31
 
33
32
 
34
33
def get_services_proto(port):
57
56
    return proto
58
57
 
59
58
 
60
 
def parse_port_proto(str):
 
59
def parse_port_proto(p_str):
61
60
    '''Parse port or port and protocol'''
62
61
    port = ""
63
62
    proto = ""
64
 
    tmp = str.split('/')
 
63
    tmp = p_str.split('/')
65
64
    if len(tmp) == 1:
66
65
        port = tmp[0]
67
66
        proto = "any"
154
153
    net = []
155
154
    changed = False
156
155
    version = "4"
 
156
    s_type = socket.AF_INET
157
157
    if v6:
158
158
        version = "6"
 
159
        s_type = socket.AF_INET6
159
160
 
160
161
    if '/' in orig:
161
162
        net = orig.split('/')
162
163
        # Remove host netmasks
163
164
        if v6 and net[1] == "128":
164
165
            del net[1]
165
 
        elif not v6:
166
 
            if net[1] == "32" or net[1] == "255.255.255.255":
167
 
                del net[1]
 
166
        elif not v6 and (net[1] == "32" or net[1] == "255.255.255.255"):
 
167
            del net[1]
168
168
    else:
169
169
        net.append(orig)
170
170
 
178
178
    addr = net[0]
179
179
 
180
180
    # Convert to packed binary, then convert back
181
 
    type = socket.AF_INET
182
 
    if v6:
183
 
        type = socket.AF_INET6
184
 
    addr = socket.inet_ntop(type, socket.inet_pton(type, addr))
 
181
    addr = socket.inet_ntop(s_type, socket.inet_pton(s_type, addr))
185
182
    if addr != net[0]:
186
183
        changed = True
187
184
 
203
200
    return (addr, changed)
204
201
 
205
202
 
206
 
def open_file_read(f):
 
203
def open_file_read(fn):
207
204
    '''Opens the specified file read-only'''
208
205
    try:
209
 
        orig = open(f, 'r')
 
206
        orig = open(fn, 'r')
210
207
    except Exception:
211
208
        raise
212
209
 
213
210
    return orig
214
211
 
215
212
 
216
 
def open_files(f):
 
213
def open_files(fn):
217
214
    '''Opens the specified file read-only and a tempfile read-write.'''
218
215
    try:
219
 
        orig = open_file_read(f)
 
216
        orig = open_file_read(fn)
220
217
    except Exception:
221
218
        raise
222
219
 
226
223
        orig.close()
227
224
        raise
228
225
 
229
 
    return { "orig": orig, "origname": f, "tmp": tmp, "tmpname": tmpname }
230
 
 
231
 
 
232
 
def write_to_file(fd, s):
 
226
    return { "orig": orig, "origname": fn, "tmp": tmp, "tmpname": tmpname }
 
227
 
 
228
 
 
229
def write_to_file(fd, out):
233
230
    '''Write to the file descriptor and error out of 0 bytes written. Intended
234
231
       to be used with open_files() and close_files().'''
235
 
    if s == "":
 
232
    if out == "":
236
233
        return
237
234
 
238
235
    if not fd:
239
236
        raise OSError(errno.ENOENT, "Not a valid file descriptor")
240
237
 
241
 
    if os.write(fd, s) <= 0:
 
238
    if os.write(fd, out) <= 0:
242
239
        raise OSError(errno.EIO, "Could not write to file descriptor")
243
240
 
244
241
 
258
255
 
259
256
    try:
260
257
        os.unlink(fns['tmpname'])
261
 
    except OSError, e:
 
258
    except OSError:
262
259
        raise
263
260
 
264
261
 
266
263
    '''Try to execute the given command.'''
267
264
    debug(command)
268
265
    try:
269
 
        sp = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
270
 
    except OSError, e:
271
 
        return [127, str(e)]
 
266
        sp = subprocess.Popen(command, stdout=subprocess.PIPE,
 
267
                              stderr=subprocess.STDOUT)
 
268
    except OSError, ex:
 
269
        return [127, str(ex)]
272
270
 
273
271
    out = sp.communicate()[0]
274
 
    return [sp.returncode,out]
 
272
    return [sp.returncode, out]
275
273
 
276
274
 
277
275
def cmd_pipe(command1, command2):
279
277
    try:
280
278
        sp1 = subprocess.Popen(command1, stdout=subprocess.PIPE)
281
279
        sp2 = subprocess.Popen(command2, stdin=sp1.stdout)
282
 
    except OSError, e:
283
 
        return [127, str(e)]
 
280
    except OSError, ex:
 
281
        return [127, str(ex)]
284
282
 
285
283
    out = sp2.communicate()[0]
286
 
    return [sp2.returncode,out]
287
 
 
288
 
 
289
 
def error(msg, exit=True):
 
284
    return [sp2.returncode, out]
 
285
 
 
286
 
 
287
def error(out, do_exit=True):
290
288
    '''Print error message and exit'''
291
289
    try:
292
 
        print >> sys.stderr, "ERROR: %s" % (msg)
 
290
        print >> sys.stderr, "ERROR: %s" % (out)
293
291
    except IOError:
294
292
        pass
295
293
 
296
 
    if exit:
 
294
    if do_exit:
297
295
        sys.exit(1)
298
296
 
299
297
 
300
 
def warn(msg):
 
298
def warn(out):
301
299
    '''Print warning message'''
302
300
    try:
303
 
        print >> sys.stderr, "WARN: %s" % (msg)
 
301
        print >> sys.stderr, "WARN: %s" % (out)
304
302
    except IOError:
305
303
        pass
306
304
 
307
305
 
308
 
def msg(msg, output=sys.stdout):
 
306
def msg(out, output=sys.stdout):
309
307
    '''Print message'''
310
308
    try:
311
 
        print >> output, "%s" % (msg)
 
309
        print >> output, "%s" % (out)
312
310
    except IOError:
313
311
        pass
314
312
 
315
313
 
316
 
def debug(msg):
 
314
def debug(out):
317
315
    '''Print debug message'''
318
 
    if debugging:
 
316
    if DEBUGGING:
319
317
        try:
320
 
            print >> sys.stderr, "DEBUG: %s" % (msg)
 
318
            print >> sys.stderr, "DEBUG: %s" % (out)
321
319
        except IOError:
322
320
            pass
323
321
 
343
341
    return word_wrap(text, 75)
344
342
 
345
343
 
346
 
def human_sort(list):
 
344
def human_sort(lst):
347
345
    '''Sorts list of strings into numeric order, with text case-insensitive.
348
346
       Modifies list in place.
349
347
 
354
352
       ['3', '80', '443', 'a2', 'a32', 'a222', 'b1', 'http', 'telnet', 'ZZZ']
355
353
    '''
356
354
    norm = lambda t: int(t) if t.isdigit() else t.lower()
357
 
    list.sort(key=lambda k: [ norm(c) for c in re.split('([0-9]+)', k)])
358
 
 
359
 
 
360
 
def get_ppid(p=os.getpid()):
 
355
    lst.sort(key=lambda k: [ norm(c) for c in re.split('([0-9]+)', k)])
 
356
 
 
357
 
 
358
def get_ppid(mypid=os.getpid()):
361
359
    '''Finds parent process id for pid based on /proc/<pid>/stat. See
362
360
       'man 5 proc' for details.
363
361
    '''
364
362
    try:
365
 
        pid = int(p)
 
363
        pid = int(mypid)
366
364
    except Exception:
367
365
        raise ValueError("pid must be an integer")
368
366
 
382
380
    '''Determine if current process is running under ssh'''
383
381
    try:
384
382
        ppid = get_ppid(pid)
385
 
    except IOError, e:
 
383
    except IOError:
386
384
        warn_msg = _("Couldn't find pid (is /proc mounted?)")
387
385
        warn(warn_msg)
388
386
        return False
463
461
            raise ValueError
464
462
 
465
463
        mbits = 0
466
 
        bits = long(struct.unpack('>L',socket.inet_aton(nm))[0])
 
464
        bits = long(struct.unpack('>L', socket.inet_aton(nm))[0])
467
465
        found_one = False
468
466
        for n in range(32):
469
467
            if (bits >> n) & 1 == 1:
502
500
        bits = 0L
503
501
        for n in range(32):
504
502
            if n < int(cidr):
505
 
                bits |= 1<<31 - n
 
503
                bits |= 1 << 31 - n
506
504
        nm = socket.inet_ntoa(struct.pack('>L', bits))
507
505
 
508
506
    if not _valid_dotted_quads(nm, v6):
532
530
            raise
533
531
 
534
532
    # Now have dotted quad host and nm, find the network
535
 
    host_bits = long(struct.unpack('>L',socket.inet_aton(host))[0])
536
 
    nm_bits = long(struct.unpack('>L',socket.inet_aton(nm))[0])
 
533
    host_bits = long(struct.unpack('>L', socket.inet_aton(host))[0])
 
534
    nm_bits = long(struct.unpack('>L', socket.inet_aton(nm))[0])
537
535
 
538
536
    network_bits = host_bits & nm_bits
539
537
    network = socket.inet_ntoa(struct.pack('>L', network_bits))
542
540
 
543
541
def _address6_to_network(addr):
544
542
    '''Convert an IPv6 address and netmask to a network address'''
545
 
    def dec2bin(n, count):
546
 
        return "".join([str((n >> y) & 1) for y in range(count-1, -1, -1)])
 
543
    def dec2bin(num, count):
 
544
        '''Decimal to binary'''
 
545
        return "".join([str((num >> y) & 1) for y in range(count-1, -1, -1)])
547
546
 
548
547
    if '/' not in addr:
549
548
        debug("_address6_to_network: skipping address without a netmask")
570
569
    nm_bits = 0L
571
570
    for i in range(128):
572
571
        if i < int(netmask):
573
 
            nm_bits |= 1<<(128 - 1) - i
 
572
            nm_bits |= 1 << (128 - 1) - i
574
573
 
575
574
    # Apply the netmask to the host to determine the network
576
575
    net = host_bits & nm_bits
589
588
    return "%s/%s" % (network, netmask)
590
589
 
591
590
 
592
 
def in_network(x, y, v6):
 
591
def in_network(tested_add, tested_net, v6):
593
592
    '''Determine if address x is in network y'''
594
 
    tmp = y.split('/')
 
593
    tmp = tested_net.split('/')
595
594
    if len(tmp) != 2 or not valid_netmask(tmp[1], v6):
596
595
        raise ValueError
597
596
 
601
600
    if orig_host == "0.0.0.0" or orig_host == "::":
602
601
        return True
603
602
 
604
 
    address = x
605
 
    if '/' in x:
606
 
        tmp = x.split('/')
 
603
    address = tested_add
 
604
    if '/' in address:
 
605
        tmp = address.split('/')
607
606
        if len(tmp) != 2 or not valid_netmask(tmp[1], v6):
608
607
            raise ValueError
609
608
        address = tmp[0]
707
706
            raise IOError(errno.ENODEV, "No such device")
708
707
    else:
709
708
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
710
 
        addr = socket.inet_ntoa(fcntl.ioctl(s.fileno(), 0x8915, \
711
 
                                struct.pack('256s', ifname[:15]))[20:24])
 
709
        try:
 
710
            addr = socket.inet_ntoa(fcntl.ioctl(s.fileno(), 0x8915, \
 
711
                                    struct.pack('256s', ifname[:15]))[20:24])
 
712
        except Exception:
 
713
            raise IOError(errno.ENODEV, "No such device")
712
714
 
713
715
    return normalize_address(addr, v6)[0]
714
716
 
716
718
def get_if_from_ip(addr):
717
719
    '''Get interface for IP address'''
718
720
    v6 = False
 
721
    proc = '/proc/net/dev'
719
722
    if valid_address6(addr):
720
723
        v6 = True
 
724
        proc = '/proc/net/if_inet6'
721
725
    elif not valid_address4(addr):
722
726
        raise IOError(errno.ENODEV, "No such device")
723
727
 
 
728
    if not os.path.exists(proc):
 
729
        raise OSError(errno.ENOENT, "'%s' does not exist" % proc)
 
730
 
724
731
    matched = ""
725
732
    if v6:
726
 
        proc = '/proc/net/if_inet6'
727
 
        if not os.path.exists(proc):
728
 
            raise OSError(errno.ENOENT, "'%s' does not exist" % proc)
729
 
 
730
733
        for line in file(proc).readlines():
731
734
            tmp = line.split()
732
735
            ifname = tmp[5].strip()
741
744
                matched = ifname
742
745
                break
743
746
    else:
744
 
        proc = '/proc/net/dev'
745
 
        if not os.path.exists(proc):
746
 
            raise OSError(errno.ENOENT, "'%s' does not exist" % proc)
747
 
 
748
747
        for line in file(proc).readlines():
749
748
            if ':' not in line:
750
749
                continue
763
762
 
764
763
 
765
764
def _get_proc_inodes():
 
765
    '''Get inodes of files in /proc'''
766
766
    proc_files = os.listdir("/proc")
767
767
    proc_files.sort()
768
768
    pat = re.compile(r'^[0-9]+$')
780
780
        exe_path = "-"
781
781
        try:
782
782
            exe_path = os.readlink(os.path.join("/proc", i, "exe"))
783
 
        except:
 
783
        except Exception:
784
784
            pass
785
785
 
786
786
        try:
791
791
        for j in dirs:
792
792
            try:
793
793
                inode = os.stat(os.path.join(fd_path, j))[1]
794
 
            except:
 
794
            except Exception:
795
795
                continue
796
796
            inodes[inode] = "%s/%s" % (i, os.path.basename(exe_path))
797
797
 
849
849
    converted = ""
850
850
    if len(paddr) > 8:
851
851
        tmp = ""
852
 
        for i in range(0,32,8):
853
 
            tmp += "".join([ paddr[j-2:j] for j in range(i+8,i,-2) ])
 
852
        for i in range(0, 32, 8):
 
853
            tmp += "".join([ paddr[j-2:j] for j in range(i+8, i, -2) ])
854
854
        converted = normalize_address(":".join( \
855
855
               [ tmp[j:j+4].lower() for j in range(0,len(tmp),4) ]), \
856
856
               True)[0]
857
857
    else:
858
858
        tmp = []
859
 
        for i in [ paddr[j-2:j] for j in range(8,0,-2) ]:
 
859
        for i in [ paddr[j-2:j] for j in range(8, 0, -2) ]:
860
860
            tmp.append(str(int(i, 16)))
861
861
        converted = normalize_address(".".join(tmp), False)[0]
862
862
 
872
872
    for p in proto:
873
873
        try:
874
874
            proc_net_data[p] = _read_proc_net_protocol(p)
875
 
        except:
 
875
        except Exception:
876
876
            warn_msg = _("Could not get statistics for '%s'" % (p))
877
877
            warn(warn_msg)
878
878
            continue
890
890
            exe = "-"
891
891
            if inodes.has_key(int(inode)):
892
892
                exe = inodes[int(inode)]
893
 
            s += "%-5s %-46s %-11s %-5s %-11s %s\n" % (p, "%s:%s" % (addr, port), state, uid, inode, exe)
 
893
            s += "%-5s %-46s %-11s %-5s %-11s %s\n" % (p,
 
894
                                                       "%s:%s" % (addr, port),
 
895
                                                       state, uid, inode, exe)
894
896
 
895
897
    return s