Changeset 6


Ignore:
Timestamp:
Mar 8, 2013 10:23:47 AM (5 years ago)
Author:
sportzer
Message:

Cleaned up ording and output code and split some of the posix specific stuff off into separate files

Location:
netcheck
Files:
3 added
1 deleted
5 edited

Legend:

Unmodified
Added
Removed
  • netcheck/README.txt

    r3 r6  
    2121 
    2222 
    23 trace_preprocessor 
     23posix_preprocessor 
    2424------------------------------------------------------------------------ 
    2525Uses generators to wrap the output of posix_test_harness_functions. This 
     
    4949connecting to 0.0.0.0, or connecting to an IPv6 address from an IPv4 
    5050address. Uses ipaddr extensively for indentifying properties of IP 
    51 addresses and uses trace_preprocessor to load preprocessed trace files. 
    52  
    53  
    54 trace_output 
    55 ------------------------------------------------------------------------ 
    56 This is where I've been moving all the logging functionality from 
    57 trace_ordering. It also now handles generating some statistic and 
    58 warnings based on the exceptions raised by the model over the course of 
    59 its execution and the final state of the model.  
     51addresses and uses posix_preprocessor to load preprocessed trace files. 
    6052 
    6153 
     
    6961 
    7062 
    71 trace_ordering 
     63posix_ordering 
    7264------------------------------------------------------------------------ 
    7365Used to run configuration files. Takes the name of a configuration file 
    7466as its only argument and feeds this name into ip_matching to initialize 
    7567the network configuration and get back a list of traces to verify. Then 
    76 the module starts feeding system calls from the traces into 
    77 model_network_syscalls to try and produce an ordering of the calls. 
    78 Uses trace_output for logging results. 
     68the module uses trace_ordering to perform the ordering. 
     69Uses posix_output for logging results. 
    7970 
     71 
     72posix_output 
     73------------------------------------------------------------------------ 
     74This is where I've been moving all the logging functionality from 
     75posix_ordering. It also now handles generating some statistic and 
     76warnings based on the exceptions raised by the model over the course of 
     77its execution and the final state of the model. 
     78 
     79 
     80trace_ordering 
     81------------------------------------------------------------------------ 
     82Used to order traces. This and trace_output are the two non posix 
     83specific files. Uses trace_output for logging results. 
     84 
     85 
     86trace_output 
     87------------------------------------------------------------------------ 
     88Contains a number of useful function for logging ordering results. 
     89 
  • netcheck/ip_matching.py

    r3 r6  
    77""" 
    88 
    9 import trace_preprocessor 
    10 import trace_output 
     9import posix_preprocessor 
    1110import ipaddr 
    1211import os.path 
     
    1615DEFAULT_IGNORE_ADDRS = [('127.0.0.1', 53)] 
    1716 
     17ENABLE_TCP_DATA_MATCHING = None 
    1818 
    1919 
     
    2727 
    2828 
    29 def initialize_hosts(config_filename): 
     29def initialize_hosts(config_filename, enable_tcp_data_matching): 
    3030  """ 
    3131  Loads a configuration file that specifies a test to verify and returns 
    3232  a dictionary of preprocessed traces to feed into the model. 
    3333  """ 
     34  global ENABLE_TCP_DATA_MATCHING 
     35  ENABLE_TCP_DATA_MATCHING = enable_tcp_data_matching 
    3436 
    3537  for ip, port in DEFAULT_IGNORE_ADDRS: 
     
    4042  config_file = open(config_filename, 'r') 
    4143  trace_dict = {} 
    42   trace_list = [] 
     44  trace_dict_copy = {} 
    4345 
    4446  print "-" * 80 
     
    116118      filename = os.path.join(base_dir, tokens[0]) 
    117119 
    118       trace = trace_preprocessor.get_trace_from_filename(filename) 
    119       trace = trace_preprocessor.preprocess_trace(trace, trace_id) 
     120      trace = posix_preprocessor.get_trace_from_filename(filename) 
     121      trace = posix_preprocessor.preprocess_trace(trace, trace_id) 
    120122      trace_dict[trace_id] = trace 
    121123 
    122       if trace_output.ENABLE_TCP_DATA_MATCHING: 
    123         trace_copy = trace_preprocessor.get_trace_from_filename(filename) 
    124         trace_copy = trace_preprocessor.preprocess_trace(trace_copy, trace_id, False) 
    125         trace_list.append(trace_copy) 
     124      if ENABLE_TCP_DATA_MATCHING: 
     125        trace_copy = posix_preprocessor.get_trace_from_filename(filename) 
     126        trace_copy = posix_preprocessor.preprocess_trace(trace_copy, trace_id, False) 
     127        trace_dict_copy[trace_id] = trace_copy 
    126128 
    127129      TRACE_INFO[trace_id] = {'name': name, 'host': host, 'file': filename} 
     
    177179  print 
    178180 
    179   if trace_output.ENABLE_TCP_DATA_MATCHING: 
    180     find_tcp_matches(trace_list) 
     181  if ENABLE_TCP_DATA_MATCHING: 
     182    find_tcp_matches(trace_dict_copy) 
    181183 
    182184  config_file.close() 
     
    185187 
    186188 
    187 def initialize_unit_test(trace_filename_list): 
     189def initialize_unit_test(trace_filename_list, enable_tcp_data_matching): 
    188190  """ 
    189191  Loads a list of trace files and initializes the network configuration 
     
    191193  host and that we don't need to specify any host IPs. 
    192194  """ 
     195  global ENABLE_TCP_DATA_MATCHING 
     196  ENABLE_TCP_DATA_MATCHING = enable_tcp_data_matching 
    193197 
    194198  for ip, port in DEFAULT_IGNORE_ADDRS: 
     
    196200 
    197201  trace_dict = {} 
    198   trace_list = [] 
     202  trace_dict_copy = {} 
    199203 
    200204  print "-" * 80 
     
    216220    print " trace", trace_id, "(" + filename + ")" 
    217221 
    218     trace = trace_preprocessor.get_trace_from_filename(filename) 
    219     trace = trace_preprocessor.preprocess_trace(trace, trace_id) 
     222    trace = posix_preprocessor.get_trace_from_filename(filename) 
     223    trace = posix_preprocessor.preprocess_trace(trace, trace_id) 
    220224    trace_dict[trace_id] = trace 
    221225 
    222     if trace_output.ENABLE_TCP_DATA_MATCHING: 
    223       trace_copy = trace_preprocessor.get_trace_from_filename(filename) 
    224       trace_copy = trace_preprocessor.preprocess_trace(trace_copy, trace_id, False) 
    225       trace_list.append(trace_copy) 
     226    if ENABLE_TCP_DATA_MATCHING: 
     227      trace_copy = posix_preprocessor.get_trace_from_filename(filename) 
     228      trace_copy = posix_preprocessor.preprocess_trace(trace_copy, trace_id, False) 
     229      trace_dict_copy[trace_id] = trace_copy 
    226230 
    227231    TRACE_INFO[trace_id] = {'name': name, 'host': 0, 'file': filename} 
     
    229233  print 
    230234 
    231   if trace_output.ENABLE_TCP_DATA_MATCHING: 
    232     find_tcp_matches(trace_list) 
     235  if ENABLE_TCP_DATA_MATCHING: 
     236    find_tcp_matches(trace_dict_copy) 
    233237 
    234238  return trace_dict 
     
    236240 
    237241 
    238 def find_tcp_matches(trace_list): 
     242def find_tcp_matches(trace_dict): 
    239243  """ 
    240244  Initializes TCP matches set with (connected socket, accepting socket) 
     
    245249  accept_sock_list = [] 
    246250 
    247   for trace in trace_list: 
    248     connect_socks, accept_socks = trace_preprocessor.get_sock_data(trace) 
     251  for trace_id in trace_dict: 
     252    connect_socks, accept_socks = posix_preprocessor.get_sock_data(trace_id, trace_dict[trace_id]) 
    249253    connect_sock_list.extend(connect_socks) 
    250254    accept_sock_list.extend(accept_socks) 
     
    279283  """ 
    280284 
    281   if trace_output.ENABLE_TCP_DATA_MATCHING: 
     285  if ENABLE_TCP_DATA_MATCHING: 
    282286    return (connecting_sock, accepting_sock) in tcp_matches 
    283287  else: 
     
    291295  """ 
    292296 
    293   if trace_output.ENABLE_TCP_DATA_MATCHING: 
     297  if ENABLE_TCP_DATA_MATCHING: 
    294298    return sock in tcp_sockets 
    295299  else: 
  • netcheck/model_network_syscalls.py

    r3 r6  
    1313# source: http://code.google.com/p/ipaddr-py/ 
    1414from ipaddr import IPAddress 
    15 import trace_output 
    1615import ip_matching 
     16 
     17from trace_ordering import SyscallException 
     18from trace_ordering import SyscallError 
     19from trace_ordering import SyscallWarning 
     20from trace_ordering import SyscallNotice 
     21from trace_ordering import SyscallDontCare 
    1722 
    1823##### GLOBALS 
     
    157162poll_timeout = set([]) 
    158163 
    159 ##### Exception Classes  
    160  
    161 class SyscallException(Exception): 
    162    """An exception raised by the model""" 
    163  
    164 class SyscallError(SyscallException): 
    165    """A system call had an error""" 
    166  
    167 class SyscallWarning(SyscallException): 
    168    """A system call had a warning""" 
    169  
    170 class SyscallDontCare(SyscallException): 
    171    """We don't care about this system call""" 
    172  
    173 class SyscallNotice(SyscallException): 
    174    """We can't do anything about it, but we should log it""" 
    175  
    176 ##### 
    177  
    178 def socket_syscall(node_name, dom, typ, prot, sockfd): 
     164 
     165 
     166def socket_syscall(node_name, args, ret): 
     167 
     168   dom, typ, prot = args 
     169   sockfd, impl_errno = ret 
    179170 
    180171   if sockfd < 0: 
     
    225216       
    226217 
    227 def bind_syscall(node_name, sock, addr, port, err): 
     218def bind_syscall(node_name, args, ret): 
     219 
     220   sock, addr, port = args 
     221   impl_ret, err = ret 
    228222 
    229223   if (node_name, sock) not in active_sockets: 
     
    302296 
    303297 
    304 def listen_syscall(node_name, sock, log, err): 
     298def listen_syscall(node_name, args, ret): 
     299 
     300   sock, log = args 
     301   impl_ret, err = ret 
    305302 
    306303   if (node_name, sock) not in active_sockets: 
     
    325322 
    326323 
    327 def accept_syscall(node_name, sock, peer_addr, peer_port, connected_socket, err): 
     324def accept_syscall(node_name, args, ret): 
     325 
     326   sock, peer_addr, peer_port = args 
     327   connected_socket, err = ret 
    328328 
    329329   if not isinstance(connected_socket, int): 
     
    357357   for require_data_matches in [True, False]: 
    358358      for require_established in [True, False]: 
    359          if (require_data_matches or require_established) and not trace_output.ENABLE_TCP_DATA_MATCHING: 
     359         if (require_data_matches or require_established) and not ip_matching.ENABLE_TCP_DATA_MATCHING: 
    360360            continue 
    361361 
     
    389389                  print " * [Warning]", warning 
    390390 
    391                if not require_data_matches and trace_output.ENABLE_TCP_DATA_MATCHING: 
     391               if not require_data_matches and ip_matching.ENABLE_TCP_DATA_MATCHING: 
    392392                  print " * [Warning] The data sent/received by this pair of sockets doesn't match" 
    393393 
     
    423423 
    424424# TODO: handle getsockopt(49, SOL_SOCKET, SO_ERROR, [111], [4]) = 0             
    425 def connect_syscall(node_name, sock, addr, port, err): 
     425def connect_syscall(node_name, args, ret): 
     426 
     427   sock, addr, port = args 
     428   impl_ret, err = ret 
    426429 
    427430   if (node_name, sock) not in active_sockets: 
     
    486489            sockets[(node_name, sock)]['state'] = 'PENDING' 
    487490            # This allows us to consider the socket if we are matching up data send/received. 
    488             if trace_output.ENABLE_TCP_DATA_MATCHING and ip_matching.is_connected_socket((node_name, sock)): 
     491            if ip_matching.ENABLE_TCP_DATA_MATCHING and ip_matching.is_connected_socket((node_name, sock)): 
    489492               try: 
    490                   connect_syscall(node_name, sock, addr, port, None) 
     493                  connect_syscall(node_name, args, (0, None)) 
    491494                  sockets[(node_name, sock)]['state'] = 'PENDING/CONNECTED' 
    492495               except SyscallException: 
     
    580583# may be used only when the socket is in a connected state 
    581584# it should only be used for IPPROTO_TCP protocol 
    582 def send_syscall(node_name, sock, msg, flags, msg_len, err): 
     585def send_syscall(node_name, args, ret): 
     586 
     587   sock, msg, flags = args 
     588   msg_len, err = ret 
    583589 
    584590   if (node_name, sock) not in active_sockets: 
     
    586592 
    587593   if sockets[(node_name, sock)]['protocol'] != IPPROTO_TCP: 
    588       return sendto_syscall(node_name, sock, msg, msg_len, flags, '', 0, err) 
     594      return sendto_syscall(node_name, (sock, msg, flags, '', 0), ret) 
    589595 
    590596   if 'PENDING' in sockets[(node_name, sock)]['state']: 
     
    592598         raise SyscallNotice("recv_syscall", 'EAGAIN/EWOULDBLOCK', "No data was sent.") 
    593599      # Node didn't actually call connect again to see that the nonblocking connect succeeded 
    594       connect_syscall(node_name, sock, sockets[(node_name, sock)]['peer_ip'], 
    595                        sockets[(node_name, sock)]['peer_port'], err) 
     600      connect_syscall(node_name, (sock, sockets[(node_name, sock)]['peer_ip'], 
     601                       sockets[(node_name, sock)]['peer_port']), ret) 
    596602 
    597603   if sockets[(node_name, sock)]['state'] != 'CONNECTED': 
     
    686692 
    687693# same: sendmsg_syscall with msg_len = len(msg) 
    688 def sendto_syscall(node_name, sock, msg, msg_len, flags, dest_addr, dest_port, err): 
     694def sendto_syscall(node_name, args, ret): 
     695 
     696   sock, msg, flags, dest_addr, dest_port = args 
     697   msg_len, err = ret 
    689698 
    690699   if (node_name, sock) not in active_sockets: 
     
    693702   # if IP addr/port is not defined, use send instead 
    694703   if sockets[(node_name, sock)]['protocol'] == IPPROTO_TCP: 
    695       send_syscall(node_name, sock, msg, flags, msg_len, err) 
     704      send_syscall(node_name, (sock, msg, flags), ret) 
    696705      if dest_addr: 
    697706         raise SyscallWarning("sendto_syscall", "EISCONN", "[Application Error] The connection-mode socket was connected already but a recipient was specified.") 
     
    812821 
    813822 
     823 
     824def sendmsg_syscall(node_name, args, ret): 
     825 
     826   sock, msg, dest_addr, dest_port, flags = args 
     827   sendto_args = sock, msg, flags, dest_addr, dest_port 
     828 
     829   return sendto_syscall(node_name, sendto_args, ret) 
     830 
     831 
     832 
     833def write_syscall(node_name, args, ret): 
     834 
     835   sock, msg = args 
     836   send_args = sock, msg, 0 
     837 
     838   return send_syscall(node_name, send_args, ret) 
     839 
     840 
     841 
     842def writev_syscall(node_name, args, ret): 
     843 
     844   sock, msg, count = args 
     845   send_args = sock, msg, 0 
     846 
     847   return send_syscall(node_name, send_args, ret) 
     848 
     849 
     850 
    814851# Implementation is not full.. I only model this for apache.. 
    815852# I assume that it sends data to TCP sockets only. Otherwise I throw an error. 
    816 def sendfile_syscall(node_name, sock, in_sock, offset, count, length, err): 
     853def sendfile_syscall(node_name, args, ret): 
     854 
     855   sock, in_sock, offset, count = args 
    817856 
    818857   # in_sock should be a file descriptor opened for reading and out_sock should be a descriptor opened for writing. 
     
    825864      raise SyscallWarning("sendfile_syscall", 'NOT_IMPLEMENTED', "I assume that it sends data to TCP sockets only.") 
    826865 
    827    return send_syscall(node_name, sock, '', 0, length, err) 
    828  
    829  
    830  
    831 def recv_syscall(node_name, sock, buf_len, flags, msg, msg_len, err): 
     866   send_args = sock, '', 0 
     867 
     868   return send_syscall(node_name, send_args, ret) 
     869 
     870 
     871 
     872def recv_syscall(node_name, args, ret): 
    832873    
     874   sock, msg, buf_len, flags = args 
     875   msg_len, err = ret 
     876 
    833877   if (node_name, sock) not in active_sockets: 
    834878      raise SyscallDontCare("recv_syscall", 'DONT_CARE', "The socket argument is not a valid file descriptor.") 
    835879 
    836880   if sockets[(node_name, sock)]['protocol'] != IPPROTO_TCP: 
    837       return recvfrom_syscall(node_name, sock, buf_len, flags, '', 0, msg, msg_len, err) 
     881      return recvfrom_syscall(node_name, (sock, msg, buf_len, flags, '', 0), ret) 
    838882 
    839883   if 'PENDING' in sockets[(node_name, sock)]['state']: 
     
    841885         raise SyscallNotice("recv_syscall", 'EAGAIN/EWOULDBLOCK', "No data was received.") 
    842886      # Node didn't actually call connect again to see that the nonblocking connect succeeded 
    843       connect_syscall(node_name, sock, sockets[(node_name, sock)]['peer_ip'], 
    844                        sockets[(node_name, sock)]['peer_port'], err) 
     887      connect_syscall(node_name, (sock, sockets[(node_name, sock)]['peer_ip'], 
     888                       sockets[(node_name, sock)]['peer_port']), ret) 
    845889 
    846890   if sockets[(node_name, sock)]['state'] != 'CONNECTED': 
     
    941985# TODO: handle flags 
    942986# same for read with flags = 0 
    943 def recvfrom_syscall(node_name, sock, buf_len, flags, rem_ip, rem_port, msg, msg_len, err): 
     987def recvfrom_syscall(node_name, args, ret): 
     988 
     989   sock, msg, buf_len, flags, rem_ip, rem_port = args 
     990   msg_len, err = ret 
    944991 
    945992   multiaddr = '' 
     
    950997   # if IP addr/port is not defined, use recv instead 
    951998   if sockets[(node_name, sock)]['protocol'] == IPPROTO_TCP: 
    952       return recv_syscall(node_name, sock, buf_len, flags, msg, msg_len, err) 
     999      return recv_syscall(node_name, (sock, msg, buf_len, flags), ret) 
    9531000 
    9541001   # when it comes to multicasting, keep only the ip addr of the group forgetting the initial remote addr 
     
    12211268       
    12221269      raise SyscallError("recvfrom_syscall", 'MSGNOTSENT', "The message has not been sent yet.") 
    1223   
    1224         
    1225 def close_syscall(node_name, sock, err): 
     1270 
     1271 
     1272 
     1273def recvmsg_syscall(node_name, args, ret): 
     1274 
     1275   sock, msg, buf_len, rem_ip, rem_port, flags = args 
     1276   recvfrom_args = sock, msg, buf_len, flags, rem_ip, rem_port 
     1277 
     1278   return recvfrom_syscall(node_name, recvfrom_args, ret) 
     1279 
     1280 
     1281 
     1282def read_syscall(node_name, args, ret): 
     1283 
     1284   sock, msg, buf_len = args 
     1285   recv_args = sock, msg, buf_len, 0 
     1286 
     1287   return recv_syscall(node_name, recv_args, ret) 
     1288 
     1289 
     1290 
     1291def close_syscall(node_name, args, ret): 
     1292 
     1293   sock, = args 
     1294   impl_ret, err = ret 
    12261295 
    12271296   if (node_name, sock) not in active_sockets: 
     
    12841353 
    12851354 
    1286 def shutdown_syscall(node_name, sock, how): 
     1355def shutdown_syscall(node_name, args, ret): 
     1356 
     1357   sock, how = args 
     1358   impl_ret, err = ret 
    12871359 
    12881360   if (node_name, sock) not in active_sockets: 
     
    13161388 
    13171389 
    1318 def setsockopt_syscall(node_name, sock, level, optname, optval): 
     1390def setsockopt_syscall(node_name, args, ret): 
     1391 
     1392   sock, level, optname, optval = args 
     1393   impl_ret, err = ret 
    13191394 
    13201395   if (node_name, sock) not in active_sockets: 
     
    14271502 
    14281503 
    1429 def getsockopt_syscall(node_name, sock, level, optname): 
     1504def getsockopt_syscall(node_name, args, ret): 
     1505 
     1506   sock, level, optname = args 
     1507   impl_ret, err = ret 
    14301508 
    14311509   if (node_name, sock) not in active_sockets: 
     
    15091587 
    15101588 
    1511 def getpeername_syscall(node_name, sock, peer_addr, peer_port): 
     1589def getpeername_syscall(node_name, args, ret): 
     1590    
     1591   sock, = args 
     1592   impl_ret, err = ret 
     1593   peer_addr, peer_port = impl_ret 
    15121594 
    15131595   if (node_name, sock) not in active_sockets: 
     
    15211603 
    15221604 
    1523 def getsockname_syscall(node_name, sock, addr, port): 
     1605def getsockname_syscall(node_name, args, ret): 
     1606    
     1607   sock, = args 
     1608   impl_ret, err = ret 
     1609   addr, port = impl_ret 
    15241610 
    15251611   if (node_name, sock) not in active_sockets: 
     
    15451631 
    15461632# I'll work only on the operation that affect our model 
    1547 def fcntl_syscall(ret, *args): 
    1548  
    1549    node_name = args[0] 
    1550    sock = args[1] 
    1551    cmd = args[2] 
     1633def fcntl_syscall(node_name, args, ret): 
     1634 
     1635   sock = args[0] 
     1636   cmd = args[1] 
    15521637 
    15531638   if (node_name, sock) not in active_sockets: 
     
    15581643 
    15591644   if cmd == F_SETFL: 
    1560       arg = args[3] 
     1645      arg = args[2] 
    15611646 
    15621647      if arg & O_NONBLOCK != 0: 
     
    15721657 
    15731658    
    1574 def ioctl_syscall(node_name, sock, command, value): 
     1659def ioctl_syscall(node_name, args, ret): 
     1660 
     1661   sock, command, value = args 
    15751662 
    15761663   if (node_name, sock) not in active_sockets: 
     
    15941681# TODO: how I should handle writefds and should I take into consideration the timeout value??     
    15951682 
    1596 def select_syscall(node_name, readfds, writefds, errorfds, timeout, ret1, ret2): 
     1683def select_syscall(node_name, args, ret): 
     1684    
     1685   readfds, writefds, errorfds, timeout = args 
     1686   ret1, ret2 = ret 
    15971687 
    15981688   if ret1 == -1: 
     
    16821772 
    16831773 
    1684 #def poll_syscall(node_name, fds, events, timeout, sock, event): 
    1685 def poll_syscall(node_name, pollin, pollout, pollerr, timeout, ret1, ret2): 
     1774 
     1775def poll_syscall(node_name, args, ret): 
     1776 
     1777   pollin, pollout, pollerr, timeout = args 
     1778   ret1, ret2 = ret 
    16861779 
    16871780   if ret1 == -1: 
     
    17841877   return False 
    17851878 
     1879 
     1880 
     1881##### System call mappings ##### 
     1882 
     1883SYSCALL_DICT = { 
     1884   'accept_syscall' :      accept_syscall, 
     1885   'bind_syscall' :        bind_syscall, 
     1886   'close_syscall' :       close_syscall, 
     1887   'connect_syscall' :     connect_syscall, 
     1888   'fcntl_syscall' :       fcntl_syscall, 
     1889   'getpeername_syscall' : getpeername_syscall, 
     1890   'getsockname_syscall' : getsockname_syscall, 
     1891   'getsockopt_syscall' :  getsockopt_syscall, 
     1892   'ioctl_syscall' :       ioctl_syscall, 
     1893   'listen_syscall' :      listen_syscall, 
     1894   'poll_syscall' :        poll_syscall, 
     1895   'read_syscall' :        read_syscall, 
     1896   'recv_syscall' :        recv_syscall, 
     1897   'recvfrom_syscall':     recvfrom_syscall, 
     1898   'recvmsg_syscall' :     recvmsg_syscall, 
     1899   'select_syscall' :      select_syscall, 
     1900   'send_syscall' :        send_syscall, 
     1901   'sendfile_syscall' :    sendfile_syscall, 
     1902   'sendmsg_syscall' :     sendmsg_syscall, 
     1903   'sendto_syscall' :      sendto_syscall, 
     1904   'setsockopt_syscall' :  setsockopt_syscall, 
     1905   'shutdown_syscall' :    shutdown_syscall, 
     1906   'socket_syscall' :      socket_syscall, 
     1907   'write_syscall' :       write_syscall, 
     1908   'writev_syscall' :      writev_syscall, 
     1909} 
     1910 
  • netcheck/trace_ordering.py

    r5 r6  
    22Steven Portzer 
    33Start Date: 07/1/2012 
     4 
    45Purpose: To order system calls from traces collected across multiple trace. 
    5 usage: python trace_ordering.py CONFIG_FILE 
     6 
    67""" 
    7 import model_network_syscalls as model 
     8 
    89import trace_output 
    9 import ip_matching 
    10 import sys 
    11  
    12  
    13 class NoValidOrderingException(Exception): 
    14   pass 
    15  
    16  
    17 # System calls that received data over the network. 
    18 RECV_SYSCALLS = [ 
    19   "recv_syscall", "recvfrom_syscall", "recvmsg_syscall", "read_syscall" 
    20 ] 
    21  
    22 # System calls that send data over the network. 
    23 SEND_SYSCALLS = [ 
    24   "send_syscall", "sendto_syscall", "sendmsg_syscall", "sendfile_syscall", 
    25   "write_syscall", "writev_syscall" 
    26 ] 
    27  
    28 # System calls whose relative ordering we care about across traces. 
    29 # PRR: Added getpeername to the list of system calls whose ordering we care about 
    30 ORDERED_SYSCALLS = RECV_SYSCALLS + SEND_SYSCALLS + [ 
    31   "accept_syscall", "connect_syscall", "close_syscall", "implicit_close", 
    32   "poll_syscall", "select_syscall", "shutdown_syscall", "listen_syscall", 
    33   "getpeername_syscall" 
    34 ] 
    35  
    36 def verify_traces(config_filename): 
    37   """ 
    38   Takes the name of a configuration file and runs the traces referenced 
    39   by the configuration file through the model. 
    40   """ 
    41   traces_generators = ip_matching.initialize_hosts(config_filename) 
    42   trace_output.log_intialize(traces_generators.keys()) 
    43    
     10 
     11 
     12##### Exception Classes  
     13 
     14class SyscallException(Exception): 
     15   """ 
     16   An exception raised by the model. Arguments are expected to be of the 
     17   form syscall_name, error_name, explaination_string. 
     18   """ 
     19 
     20class SyscallError(SyscallException): 
     21   """ 
     22   A system call would result in an error that should match an error 
     23   raised by the implementation. 
     24   """ 
     25 
     26class SyscallWarning(SyscallException): 
     27   """ 
     28   A system call would result in an error, but we can't do anything 
     29   about it so we should continue regardless. 
     30   """ 
     31 
     32class SyscallNotice(SyscallException): 
     33   """ 
     34   A system call would result in some sort of problem, but it's not 
     35   particular severe we can't do anything about it so we should continue. 
     36   """ 
     37 
     38class SyscallDontCare(SyscallException): 
     39   """ 
     40   We don't care about this system call. 
     41   """ 
     42 
     43 
     44class OrderingFailedException(Exception): 
     45  """ 
     46  No valid ordering of the system calls was found. 
     47  """ 
     48 
     49  def __init__(self, string, syscall_err_list): 
     50    self.syscall_err_list = syscall_err_list 
     51    Exception.__init__(self, string) 
     52 
     53 
     54 
     55def verify_traces(trace_dict, model, priority=None): 
     56  """ 
     57  <Purpose> 
     58    Attempts to produce a valid ordering of the traces. 
     59 
     60  <Arguments> 
     61    trace_dict: 
     62      A dictionary mapping trace IDs to iterable objects that yield 
     63      (syscall_name, args, ret) tuples. 
     64    model: 
     65      A dictionary mapping syscall names to functions of the form 
     66      syscall_name(trace_id, args, ret) that return expected ret values. 
     67    priority: 
     68      If specified, a function priority(trace_id, syscall_name, args, ret) 
     69      that returns numerical values. The lower the value, the more we prefer 
     70      to consume that system call. 
     71 
     72  <Exceptions> 
     73    OrderingFailedException if no valid ordering is found. 
     74 
     75  <Returns> 
     76    None. 
     77  """ 
     78 
     79  trace_output.log_intialize() 
     80 
     81  traces_iter_dict = {} 
     82  for trace_id in trace_dict: 
     83    traces_iter_dict[trace_id] = iter(trace_dict[trace_id]) 
     84 
    4485  syscall_dict = {} 
    45    
    46   for trace_id in traces_generators: 
     86 
     87  for trace_id in traces_iter_dict: 
    4788    try: 
    48       syscall_dict[trace_id] = traces_generators[trace_id].next() 
     89      syscall_dict[trace_id] = traces_iter_dict[trace_id].next() 
    4990    except StopIteration: 
    5091      pass 
    51      
     92 
    5293  while syscall_dict: 
    53     next_syscall_index = choose_next_syscall(syscall_dict.values()) 
    54      
     94    next_syscall_id = choose_next_syscall(syscall_dict, model, priority) 
     95 
    5596    try: 
    56       syscall_dict[next_syscall_index] = traces_generators[next_syscall_index].next() 
     97      syscall_dict[next_syscall_id] = traces_iter_dict[next_syscall_id].next() 
    5798    except StopIteration: 
    58       del syscall_dict[next_syscall_index] 
     99      del syscall_dict[next_syscall_id] 
    59100 
    60101  trace_output.log_done() 
    61    
    62    
    63 def verify_unit_test(trace_filenames): 
    64   """ 
    65   Takes a list of traces produced by a unit test and runs them through 
    66   the model. 
    67   """ 
    68   traces_generators = ip_matching.initialize_unit_test(trace_filenames) 
    69  
    70   trace_output.log_intialize(traces_generators.keys()) 
    71    
    72   syscall_dict = {} 
    73    
    74   for trace_id in traces_generators: 
     102 
     103 
     104 
     105def choose_next_syscall(syscall_dict, model, priority=None): 
     106  """ 
     107  <Purpose> 
     108    Takes a list of system call tuples and decides which of these calls 
     109    to do next. 
     110 
     111  <Arguments> 
     112    syscall_dict: 
     113      A dictionary mapping trace IDs to (syscall_name, args, ret) tuples 
     114      that we should choose between. 
     115    model: 
     116      A dictionary mapping syscall names to functions of the form 
     117      syscall_name(trace_id, args, ret) that return expected ret values. 
     118    priority: 
     119      If specified, a function priority(trace_id, syscall_name, args, ret) 
     120      that returns numerical values. The lower the value, the more we prefer 
     121      to consume that system call. 
     122 
     123  <Exceptions> 
     124    OrderingFailedException if no valid ordering is found. 
     125 
     126  <Returns> 
     127    The trace ID of the chosen system call. 
     128  """ 
     129 
     130  syscall_list = syscall_dict.items() 
     131 
     132  # Sort the system calls based on priority. 
     133  if priority: 
     134    def syscall_key(item): 
     135      trace_id, syscall = item 
     136      name, args, ret = syscall 
     137      return priority(trace_id, name, args, ret) 
     138 
     139    syscall_list.sort(key=syscall_key) 
     140 
     141  syscall_err_list = [] 
     142 
     143  for trace_id, syscall in syscall_list: 
    75144    try: 
    76       syscall_dict[trace_id] = traces_generators[trace_id].next() 
    77     except StopIteration: 
    78       pass 
    79      
    80   while syscall_dict: 
    81     next_syscall_index = choose_next_syscall(syscall_dict.values()) 
    82     try: 
    83       syscall_dict[next_syscall_index] = traces_generators[next_syscall_index].next() 
    84     except StopIteration: 
    85       del syscall_dict[next_syscall_index] 
    86  
    87   trace_output.log_done() 
    88    
    89  
    90 def choose_next_syscall(syscall_list): 
    91   """ 
    92   Takes a list of system call tuples and decides which of these calls to 
    93   do next. The trace id for the system call we decided to perform is 
    94   returned, or if no action is possible an exception is raised. 
    95   """ 
    96   syscall_list.sort(key=syscall_priority) 
    97    
    98   for syscall in syscall_list: 
    99     if verify_syscall(syscall): 
    100       return syscall[1][0] 
    101      
    102   syscall_err_list = [] 
    103    
    104   for syscall in syscall_list: 
    105     err = get_syscall_err(syscall) 
    106     syscall_err_list.append((syscall, err)) 
    107      
     145      model_call(trace_id, syscall, model) 
     146 
     147    # We can't continue past errors. 
     148    except SyscallError, err: 
     149      trace_output.log_syscall_attempt(trace_id, syscall, err) 
     150      syscall_err_list.append((trace_id, syscall, err)) 
     151 
     152    # Other exceptions should be logged, but we shouldn't try to 
     153    # execute the call again. 
     154    except SyscallException, err: 
     155      trace_output.log_syscall(trace_id, syscall, err) 
     156      return trace_id 
     157 
     158    # The call succeeded without any unusual behavior. 
     159    else: 
     160      trace_output.log_syscall(trace_id, syscall) 
     161      return trace_id 
     162 
     163  # We can't do anything, so ordering failed 
    108164  trace_output.log_execution_blocked(syscall_err_list) 
    109    
    110   raise NoValidOrderingException("No valid action exists") 
    111  
    112 def syscall_priority(syscall): 
    113   """ 
    114   Returns the priority of the system call. The lower the number, the 
    115   higher the priority. 
     165  raise OrderingFailedException("No valid action found.", syscall_err_list) 
     166 
     167 
     168 
     169def model_call(trace_id, syscall, model): 
     170  """ 
     171  <Purpose> 
     172    Tries to execute a system call. 
     173 
     174  <Arguments> 
     175    trace_id: 
     176      A identifier for the trace the system call belongs to. 
     177    syscall: 
     178      A (syscall_name, args, ret) tuple to execute. 
     179    model: 
     180      A dictionary mapping syscall names to functions of the form 
     181      syscall_name(trace_id, args, ret) that return expected ret values. 
     182 
     183  <Exceptions> 
     184    SyscallException if the system call causes the model to raise an 
     185      exception or misbehave. 
     186 
     187  <Returns> 
     188    None. 
    116189  """ 
    117190 
    118191  name, args, ret = syscall 
    119    
    120   if name not in ORDERED_SYSCALLS: 
    121     return 0 
    122    
    123   if name == 'select_syscall': 
    124     if model.care_about_fd_list(args[0], args[1]) and (isinstance(ret[0], int) 
    125         or model.care_about_fd_list(args[0], ret[0])): 
    126       return 1 
    127      
    128     #PRR: Select system call now dependent on recv/read 
    129     elif name in RECV_SYSCALLS: 
    130       return 1 
    131      
    132     else: # Don't care about the call 
    133       return 0 
    134      
    135   if name == 'poll_syscall': 
    136     if model.care_about_fd_list(args[0], args[1]) and (isinstance(ret[0], int) 
    137         or model.care_about_fd_list(args[0], ret[0][0])): 
    138       return 1 
    139      
    140     #PRR: Poll System call now dependent on recv/read 
    141     elif name in RECV_SYSCALLS: 
    142       return 1 
    143      
    144     else: # Don't care about the call 
    145       return 0 
    146      
    147   # Make sure the socket is one we care about. 
    148   sock = syscall[1][:2] 
    149   if sock not in model.active_sockets: 
    150     return 0 
    151  
    152   socket = model.sockets[sock] 
    153    
    154   # Make sure if there is a remote address involved that we care about it. 
    155   ip, port = None, None 
    156   if name == 'accept_syscall': 
    157     trace_id, fd, ip, port = args 
    158      
    159   elif name == 'recvfrom_syscall': 
    160     trace_id, sock, msg, buf_len, flags, ip, port = args 
    161      
    162   elif name == 'recvmsg_syscall': 
    163     trace_id, sock, msg, buf_len, ip, port, flags = args 
    164      
    165   elif name == 'connect_syscall': 
    166     trace_id, sock, ip, port = args 
    167      
    168   elif name == 'sendto_syscall': 
    169     trace_id, sock, msg, flags, ip, port = args 
    170      
    171   elif name == "sendmsg_syscall": 
    172     trace_id, sock, msg, ip, port, flags = args 
    173      
    174   if not ip and socket['protocol'] == model.IPPROTO_UDP and name in SEND_SYSCALLS: 
    175     ip, port = socket['peer_ip'], socket['peer_port'] 
    176      
    177   if ip and ip not in model.broadcast_ip and ip_matching.addr_dont_care(ip, port): 
    178     return 0 
    179    
    180   # We care about these calls, so now order them according to our rules. 
    181   if name == 'accept_syscall': 
    182     return 1 
    183    
    184   elif name in RECV_SYSCALLS: 
    185     return 1 
    186    
    187   elif name == 'connect_syscall': 
    188     if socket['protocol'] == model.IPPROTO_UDP: 
    189       return 0 
    190     return 2 
    191    
    192   elif name in SEND_SYSCALLS: 
    193     return 2 
    194  
    195   #PRR: getpeername now has a lower priority - dependent on close 
    196   elif name == 'listen_syscall' or name == 'getpeername_syscall': 
    197     return 3 
    198    
    199   elif name in ["close_syscall", "implicit_close", "shutdown_syscall"]: 
    200     if socket['state'] not in ['CONNECTED', 'LISTEN']: 
    201       return 0 
    202     return 3 
    203    
    204   raise Exception("Failed to handle priority of " + name) 
    205  
    206  
    207 def verify_syscall(syscall): 
    208   """ 
    209   Tries to preform the given system call. If it succeeds True is returned 
    210   and the model is updated accordingly. Otherwise, False is returned and 
    211   the model is not updated. 
    212   """ 
     192  impl_ret, impl_errno = ret 
     193 
    213194  try: 
    214     model_call(syscall) 
    215      
    216   except model.SyscallError, err: 
    217     trace_output.log_syscall_attempt(syscall, err) 
    218     return False 
    219    
    220   except model.SyscallException, err: 
    221     trace_output.log_syscall(syscall, err) 
    222      
    223   else: 
    224     trace_output.log_syscall(syscall) 
    225      
    226   return True 
    227  
    228  
    229 def get_syscall_err(syscall): 
    230   """ 
    231   Returns the Exception, if any, raised by executing the system call in 
    232   the model. 
    233   """ 
    234   try: 
    235     model_call(syscall) 
    236      
    237   except Exception, err: 
    238     return err 
    239  
    240    
    241 def model_call(syscall): 
    242   """ 
    243   Takes a given system call and attempts to execute it in the posix model. 
    244   If we fail to model the call then we raise SyscallError, SyscallWarning, 
    245   or SyscallDontCare depending on what failed. 
    246   """ 
    247   name, args, ret = syscall 
    248    
    249   impl_ret, impl_errno = ret 
    250    
    251   try: 
    252      
    253     ##### SOCKET ##### 
    254     if name == 'socket_syscall': 
    255       trace_id, dom, typ, prot = args 
    256       model_ret = model.socket_syscall(trace_id, dom, typ, prot, impl_ret) 
    257        
    258     ##### BIND ##### 
    259     elif name == 'bind_syscall': 
    260       trace_id, sock, addr, port = args 
    261       model_ret = model.bind_syscall(trace_id, sock, addr, port, impl_errno) 
    262        
    263     ##### LISTEN ##### 
    264     elif name == 'listen_syscall': 
    265       trace_id, sock, log = args 
    266       model_ret = model.listen_syscall(trace_id, sock, log, impl_errno) 
    267        
    268     ##### ACCEPT ##### 
    269     elif name == 'accept_syscall': 
    270       trace_id, fd, ip, port = args 
    271       model_ret = model.accept_syscall(trace_id, fd, ip, port, impl_ret, impl_errno) 
    272        
    273     ##### CONNECT ##### 
    274     elif name == 'connect_syscall': 
    275       trace_id, sock, addr, port = args 
    276       model_ret = model.connect_syscall(trace_id, sock, addr, port, impl_errno) 
    277        
    278     ##### SEND ##### 
    279     elif name == 'send_syscall': 
    280       trace_id, sock, msg, flag = args 
    281       model_ret = model.send_syscall(trace_id, sock, msg, flag, impl_ret, impl_errno) 
    282     
    283     ##### WRITE ##### 
    284     elif name == 'write_syscall': 
    285       trace_id, sock, msg = args 
    286       model_ret = model.send_syscall(trace_id, sock, msg, 0, impl_ret, impl_errno) 
    287     
    288     ##### WRITEV ##### 
    289     elif name == 'writev_syscall': 
    290       trace_id, sock, msg, count = args 
    291       model_ret = model.send_syscall(trace_id, sock, msg, 0, impl_ret, impl_errno) 
    292        
    293     ##### SENDTO ##### 
    294     elif name == 'sendto_syscall': 
    295       trace_id, sock, msg, flags, remoteip, remoteport = args 
    296       model_ret = model.sendto_syscall(trace_id, sock, msg, impl_ret, flags, remoteip, remoteport, impl_errno) 
    297        
    298     ##### SENDMSG ##### 
    299     elif name == "sendmsg_syscall": 
    300       trace_id, sock, msg, remoteip, remoteport, flags = args 
    301       model_ret = model.sendto_syscall(trace_id, sock, msg, impl_ret, flags, remoteip, remoteport, impl_errno) 
    302        
    303     ##### SENDFILE ##### 
    304     elif name == "sendfile_syscall": 
    305       trace_id, out_sock, in_sock, offset, count = args 
    306       model_ret = model.sendfile_syscall(trace_id, out_sock, in_sock, offset, count, impl_ret, impl_errno) 
    307        
    308     ##### RECVFROM ##### 
    309     elif name == 'recvfrom_syscall': 
    310       trace_id, sock, msg, buf_len, flags, ip, port = args 
    311       model_ret = model.recvfrom_syscall(trace_id, sock, buf_len, flags, ip, port, msg, impl_ret, impl_errno) 
    312        
    313     ##### RECVMSG ##### 
    314     elif name == "recvmsg_syscall": 
    315       trace_id, sock, msg, buf_len, remoteip, remoteport, flags = args 
    316       model_ret = model.recvfrom_syscall(trace_id, sock, buf_len, flags, remoteip, remoteport, msg, impl_ret, impl_errno) 
    317        
    318     ##### RECV ##### 
    319     elif name == 'recv_syscall': 
    320       trace_id, sock, msg, buf_len, flag = args 
    321       model_ret = model.recv_syscall(trace_id, sock, buf_len, flag, msg, impl_ret, impl_errno) 
    322        
    323     ##### READ ##### 
    324     elif name == 'read_syscall': 
    325       trace_id, sock, msg, buf_len = args 
    326       model_ret = model.recv_syscall(trace_id, sock, buf_len, 0, msg, impl_ret, impl_errno) 
    327        
    328     ##### CLOSE ##### 
    329     elif name == 'close_syscall' or name == 'implicit_close': 
    330       trace_id, sock = args 
    331       model_ret = model.close_syscall(trace_id, sock, impl_errno) 
    332        
    333     ##### SETSOCKOPT ##### 
    334     elif name == 'setsockopt_syscall': 
    335       trace_id, sockfd, level, optname, optval = args 
    336       model_ret = model.setsockopt_syscall(trace_id, sockfd, level, optname, optval) 
    337        
    338     ##### GETSOCKOPT ##### 
    339     elif name == 'getsockopt_syscall': 
    340       trace_id, sockfd, level, optname = args 
    341       model_ret = model.getsockopt_syscall(trace_id, sockfd, level, optname) 
    342        
    343     ##### GETPEERNAME ##### 
    344     elif name == 'getpeername_syscall': 
    345       trace_id, sock = args 
    346       peer_addr, peer_port = impl_ret 
    347       model_ret = model.getpeername_syscall(trace_id, sock, peer_addr, peer_port) 
    348        
    349     ##### GETSOCKNAME ##### 
    350     elif name == 'getsockname_syscall': 
    351       trace_id, sock = args 
    352       sock_ip, sock_port = impl_ret 
    353       model_ret = model.getsockname_syscall(trace_id, sock, sock_ip, sock_port) 
    354        
    355     ##### IOCTL ##### 
    356     elif name == 'ioctl_syscall': 
    357       trace_id, fd, cmd, val = args 
    358       model_ret = model.ioctl_syscall(trace_id, fd, cmd, val) 
    359        
    360     ##### FCNTL ##### 
    361     elif name == 'fcntl_syscall': 
    362       model_ret = model.fcntl_syscall(impl_ret, *args) 
    363        
    364     ##### SELECT ##### 
    365     elif name == 'select_syscall': 
    366       trace_id, readfds, writefds, errorfds, timeout = args 
    367       model_ret = model.select_syscall(trace_id, readfds, writefds, errorfds, timeout, impl_ret, impl_errno) 
    368        
    369     ##### POLL ##### 
    370     elif name == 'poll_syscall': 
    371       trace_id, new_pollin, new_pollout, new_pollerr, timeout = args 
    372       model_ret = model.poll_syscall(trace_id, new_pollin, new_pollout, new_pollerr, timeout, impl_ret, impl_errno) 
    373        
    374     ##### SHUTDOWN ##### 
    375     elif name == 'shutdown_syscall': 
    376       trace_id, sock, how = args 
    377       model_ret = model.shutdown_syscall(trace_id, sock, how) 
     195    if name in model: 
     196      model_ret = model[name](trace_id, args, ret) 
    378197    else: 
    379       raise model.SyscallNotice(name, 'UNKNOWN_SYSCALL', "'" + name + "' is not a recognized system call.") 
    380      
    381      
    382   except model.SyscallError, err: 
     198      # This system call isn't in our model. 
     199      raise SyscallNotice(name, 'UNKNOWN_SYSCALL', "'" + name + "' is not a recognized system call.") 
     200 
     201  # If the error raised by the model matches the error raised by the 
     202  # implementation, then we can continue. Otherwise, we can't continue 
     203  # past this system call. 
     204  except SyscallError, err: 
    383205    if impl_ret == -1 and isinstance(impl_errno, str) and impl_errno in err.args[1]: 
    384206      return 
    385207    raise err 
    386    
     208 
     209  # The model shouldn't be able to succeed if the implementation raised 
     210  # an error, but we can't backtrack so we will continue past this call. 
    387211  if impl_ret == -1: 
    388     raise model.SyscallWarning(name, 'UNEXPECTED_SUCCESS', "Model succeeded but implementation failed.") 
    389    
     212    raise SyscallWarning(name, 'UNEXPECTED_SUCCESS', "Model succeeded but implementation failed.") 
     213 
     214  # The model should return the same result as the implementation, but 
     215  # we can't backtrack so we will continue past this call. 
    390216  if impl_ret != model_ret[0]: 
    391     raise model.SyscallWarning(name, 'UNEXPECTED_RETURN_VALUE', "Model returned " + str(model_ret[0])) 
    392  
    393    
    394 def main(): 
    395   if len(sys.argv) >= 2 and sys.argv[1] == '-u': 
    396      
    397     try: 
    398       verify_unit_test(sys.argv[2:]) 
    399        
    400     except NoValidOrderingException: 
    401       pass 
    402      
    403   elif len(sys.argv) == 2: 
    404     try: 
    405       verify_traces(sys.argv[1]) 
    406        
    407     except NoValidOrderingException: 
    408       pass 
    409   else: 
    410     print "usage: python trace_ordering.py CONFIG_FILE" 
    411  
    412      
    413 if __name__ == "__main__": 
    414   main() 
     217    raise SyscallWarning(name, 'UNEXPECTED_RETURN_VALUE', "Model returned " + str(model_ret[0])) 
     218 
     219 
  • netcheck/trace_output.py

    r3 r6  
    77""" 
    88 
    9 import model_network_syscalls as model 
     9import trace_ordering 
    1010from ip_matching import format_addr 
    1111from ip_matching import addr_dont_care 
    1212from ip_matching import is_addr_match 
    13  
    14  
    15  
    16 ##### Model Configuration ##### 
    17  
    18 # Inspect the send and receive calls made within traces to better match 
    19 # up TCP connections. 
    20 ENABLE_TCP_DATA_MATCHING = True 
    2113 
    2214 
     
    3325SHOW_SYSCALLS = False 
    3426 
    35 # Don't print system calls we don't care about 
     27# If SHOW_SYSCALLS is True, still don't print system calls we don't care about 
    3628SUPPRESS_DONTCARE = False 
    3729 
    38 # Don't print failed attempts of system calls (calls that cause the 
    39 # model to raise an error and must be reattempted later) 
     30# If SHOW_SYSCALLS is True, still don't print failed attempts of system 
     31# calls (calls that cause the model to raise an error and must be 
     32# reattempted later) 
    4033SUPPRESS_ATTEMPTS = False 
    4134 
    4235 
    43 # If not None, only print this many characters of sent/received strings 
     36# If not None, only print this many characters of string arguments 
    4437MAX_STRING_LEN = 32 
    45  
    46  
    47 # Print all the details of the model's state once verificantion finishes 
    48 PRINT_MODEL_STATE = False 
    49  
    50 # Print general statistics on the amount of data sent/received 
    51 PRINT_STATISTICS = True 
    5238 
    5339###################################### 
     
    5541 
    5642 
    57 # System calls that received data over the network. 
    58 RECV_SYSCALLS = [ 
    59   "recv_syscall", "recvfrom_syscall", "recvmsg_syscall", "read_syscall" 
    60 ] 
    61  
    62 # System calls that send data over the network. 
    63 SEND_SYSCALLS = [ 
    64   "send_syscall", "sendto_syscall", "sendmsg_syscall", "sendfile_syscall", 
    65   "write_syscall", "writev_syscall" 
    66 ] 
    67  
    68  
    69  
    70 # Exceptions that occur during execution of the traces. 
    71 exception_list = [] 
    72  
    73 # Ignored connect calls 
    74 dontcare_connect_list = [] 
    75  
    76 # Ignored accept calls 
    77 dontcare_accept_list = [] 
    78  
    79 # Maps sockets to the number of time that socket tried to write and got EPIPE or ECONNRESET 
    80 send_after_closed_dict = {} 
    81  
    82 # A dict of booleans specifying which traces have had network traffic we care about 
    83 trace_has_traffic = {} 
    84  
    85 # A dict of booleans specifying which traces have had network traffic we don't care about 
    86 has_dontcare_traffic = {} 
    87  
    88  
    89  
    90 def log_intialize(trace_ids): 
    91  
    92   for trace_id in trace_ids: 
    93     trace_has_traffic[trace_id] = False 
    94     has_dontcare_traffic[trace_id] = False 
     43def log_intialize(): 
     44  """ 
     45  Starts logging ordering information. 
     46  """ 
    9547 
    9648  print "-" * 80 
     
    9951 
    10052 
    101 def log_syscall(syscall, err=None): 
     53 
     54def log_syscall(trace_id, syscall, err=None): 
     55  """ 
     56  Logs the result of a system call. 
     57  """ 
    10258 
    10359  name, args, ret = syscall 
    104   trace_id = args[0] 
    105  
    106   sock = None 
    107   if name in RECV_SYSCALLS or name in SEND_SYSCALLS or \ 
    108       name == "accept_syscall" or name == "connect_syscall": 
    109     if args[:2] in model.sockets: 
    110       sock = model.sockets[args[:2]] 
    11160 
    11261  if err is None: 
     
    11463      print "trace", str(trace_id) + ":", shorten_syscall(syscall) 
    11564 
    116     if sock and (name != "connect_syscall" or sock['protocol'] == model.IPPROTO_TCP): 
    117       trace_has_traffic[trace_id] = True 
    118  
    119     if name in SEND_SYSCALLS and (ret == (-1, 'EPIPE') or ret == (-1, 'ECONNRESET')): 
    120       send_after_closed_dict.setdefault(args[:2], 0) 
    121       send_after_closed_dict[args[:2]] += 1 
    122  
    123   elif isinstance(err, model.SyscallDontCare): 
    124     if name == 'connect_syscall': 
    125       dontcare_connect_list.append(syscall) 
    126     elif name == 'accept_syscall': 
    127       dontcare_accept_list.append(syscall) 
    128  
    129     if sock and (name != "connect_syscall" or sock['protocol'] == model.IPPROTO_TCP): 
    130       has_dontcare_traffic[trace_id] = True 
     65  elif isinstance(err, trace_ordering.SyscallDontCare): 
    13166 
    13267    if SHOW_SYSCALLS and not SUPPRESS_DONTCARE: 
    13368      print "[Don't Care] trace", str(trace_id) + ":", shorten_syscall(syscall) 
    13469 
    135   elif isinstance(err, model.SyscallNotice): 
     70  elif isinstance(err, trace_ordering.SyscallNotice): 
    13671    if SHOW_SYSCALLS or SHOW_NOTICES: 
    13772      print "[Notice] trace", str(trace_id) + ":", shorten_syscall(syscall) 
    13873      print "   => %s: %s" % err.args[1:] 
    139     exception_list.append((syscall, err)) 
    14074 
    141   elif isinstance(err, model.SyscallWarning): 
     75  elif isinstance(err, trace_ordering.SyscallWarning): 
    14276    if SHOW_SYSCALLS or SHOW_WARNINGS: 
    14377      print "[Warning] trace", str(trace_id) + ":", shorten_syscall(syscall) 
    14478      print "   => %s: %s" % err.args[1:] 
    145     exception_list.append((syscall, err)) 
    146  
    147     if err.args[1] == 'EPIPE/ECONNRESET': 
    148       send_after_closed_dict.setdefault(args[:2], 0) 
    149       send_after_closed_dict[args[:2]] += 1 
    15079 
    15180  elif isinstance(err, model.SyscallError): 
    15281    print "[Error] trace", str(trace_id) + ":", shorten_syscall(syscall) 
    15382    print "   => %s: %s" % err.args[1:] 
    154     exception_list.append((syscall, err)) 
    15583 
    15684 
    157 def log_syscall_attempt(syscall, err): 
     85 
     86def log_syscall_attempt(trace_id, syscall, err): 
     87  """ 
     88  Logs a failed attempt to execute a system call. 
     89  """ 
    15890 
    15991  if SUPPRESS_ATTEMPTS or not SHOW_SYSCALLS: 
     
    16193 
    16294  name, args, ret = syscall 
    163   trace_id = args[0] 
    16495 
    16596  print "[Failed to Execute] trace", str(trace_id) + ":", shorten_syscall(syscall) 
     
    16798 
    16899 
    169 def log_unexpected_success(syscall, model_ret): 
    170  
    171   print 
    172   print "Model successfully executed system call but trace contains an error!" 
    173   print "[Error] trace", str(syscall[1][0]) + ":", shorten_syscall(syscall) 
    174   print "   => UNEXPECTED_RETURN_VALUE: Model returned ", model_ret 
    175   exception_list.append((syscall, 
    176       model.SyscallNotice(syscall[0], 'UNEXPECTED_SUCCESS', "Model succeeded but implementation failed"))) 
    177  
    178   analyze_results(True) 
    179  
    180100 
    181101def log_execution_blocked(syscall_list): 
     102  """ 
     103  Logs failure of system call ordering. 
     104  """ 
    182105 
    183106  print 
    184107  print "No valid action:" 
    185   for syscall, err in syscall_list: 
    186     trace_id = syscall[1][0] 
     108  for trace_id, syscall, err in syscall_list: 
    187109    print "[Error] trace", str(trace_id) + ":", shorten_syscall(syscall) 
    188110    print "   => %s: %s" % err.args[1:] 
    189     exception_list.append((syscall, err)) 
    190111 
    191   analyze_results(True) 
    192112 
    193113 
    194114def log_done(): 
     115  """ 
     116  Logs successful completion of system call ordering. 
     117  """ 
    195118 
    196119  print 
    197120  print "Done" 
    198  
    199   analyze_results(False) 
    200121 
    201122 
     
    207128 
    208129  name, args, ret = syscall 
    209  
    210   if name == 'send_syscall': 
    211     trace_id, sock, msg, flag = args 
    212     args = trace_id, sock, shorten_string(msg), flag 
    213  
    214   elif name == 'write_syscall': 
    215     trace_id, sock, msg = args 
    216     args = trace_id, sock, shorten_string(msg) 
    217  
    218   elif name == 'writev_syscall': 
    219     trace_id, sock, msg, count = args 
    220     args = trace_id, sock, shorten_string(msg), count 
    221  
    222   elif name == 'sendto_syscall': 
    223     trace_id, sock, msg, flags, remoteip, remoteport = args 
    224     args = trace_id, sock, shorten_string(msg), flags, remoteip, remoteport 
    225  
    226   elif name == 'sendmsg_syscall': 
    227     trace_id, sock, msg, remoteip, remoteport, flags = args 
    228     args = trace_id, sock, shorten_string(msg), remoteip, remoteport, flags 
    229  
    230   elif name == 'recvfrom_syscall': 
    231     trace_id, sock, msg, buf_len, flags, ip, port = args 
    232     args = trace_id, sock, shorten_string(msg), buf_len, flags, ip, port 
    233  
    234   elif name == 'recvmsg_syscall': 
    235     trace_id, sock, msg, buf_len, ip, port, flags = args 
    236     args = trace_id, sock, shorten_string(msg), buf_len, ip, port, flags 
    237  
    238   elif name == 'recv_syscall': 
    239     trace_id, sock, msg, buf_len, flags = args 
    240     args = trace_id, sock, shorten_string(msg), buf_len, flags 
    241  
    242   elif name == 'read_syscall': 
    243     trace_id, sock, msg, buf_len = args 
    244     args = trace_id, sock, shorten_string(msg), buf_len 
    245  
     130  args = tuple(map(shorten_string, args)) 
     131   
    246132  return name, args, ret 
    247133 
    248134 
    249 def shorten_string(string): 
     135 
     136def shorten_string(obj): 
    250137  """ 
    251   Returns the string, abridged if neccessary. 
     138  Returns the object, abridged if neccessary. 
    252139  """ 
    253140 
    254   if isinstance(string, str) and MAX_STRING_LEN and len(string) > MAX_STRING_LEN: 
    255     return string[:MAX_STRING_LEN] + "..." 
     141  if isinstance(obj, str) and MAX_STRING_LEN and len(obj) > MAX_STRING_LEN: 
     142    return obj[:MAX_STRING_LEN] + "..." 
    256143  else: 
    257     return string 
     144    return obj 
    258145 
    259  
    260  
    261 def analyze_results(parsing_failed): 
    262  
    263   errors = [] 
    264  
    265   if parsing_failed: 
    266     errors.append("The model failed to process the entire trace") 
    267  
    268   print_model_state() 
    269  
    270   errors += check_possible_nats(parsing_failed) 
    271   errors += check_tcp_buffers() 
    272   errors += check_udp_buffers() 
    273   errors += check_exceptions() 
    274  
    275   print 
    276   print "-" * 80 
    277   print "Possible Problems Detected" 
    278   print "-" * 80 
    279   for error in errors: 
    280     print " * " + error 
    281  
    282   if not errors: 
    283     print " * None" 
    284   else: 
    285     print 
    286     print "For more details, adjust the variables defined in trace_output.py to change the level of output" 
    287  
    288  
    289  
    290 def check_possible_nats(parsing_failed): 
    291  
    292   errors = [] 
    293  
    294   possible_nats = False 
    295   found_something = False 
    296   accept_dict = {} 
    297   connect_dict = {} 
    298  
    299   if exception_list: 
    300     last_syscall, last_err = exception_list[-1] 
    301     if last_syscall[0] == 'connect_syscall' and last_err.args[1] == 'UNEXPECTED_SUCCESS': 
    302       bad_fd = last_syscall[1][:2] 
    303       for a_sock in model.pending_connections: 
    304         if bad_fd in model.pending_connections[a_sock]: 
    305           model.pending_connections[a_sock].remove(bad_fd) 
    306  
    307   for a_sock in model.pending_connections: 
    308     for c_sock in model.pending_connections[a_sock][:]: 
    309       if model.sockets[c_sock]['state'] != 'CONNECTED': 
    310         model.pending_connections[a_sock].remove(c_sock) 
    311  
    312   for name, args, ret in dontcare_accept_list: 
    313     if ret[0] != -1: 
    314       accept_dict.setdefault(args[:2], set()).add(args[2]) 
    315  
    316   for a_sock in model.pending_connections: 
    317     if model.pending_connections[a_sock]: 
    318       print 
    319       print "-" * 80 
    320       print "Network Configuration Issues" 
    321       print "-" * 80 
    322       found_something = True 
    323       break 
    324  
    325   for a_sock in model.pending_connections: 
    326     pending = model.pending_connections[a_sock] 
    327     if not pending: 
    328       continue 
    329  
    330     pending_dict = {} 
    331     for sock in pending: 
    332       key = (sock[0], model.sockets[sock]['peer_ip'], model.sockets[sock]['peer_port']) 
    333       pending_dict.setdefault(key, 0) 
    334       pending_dict[key] += 1 
    335  
    336     local_addr = format_addr(model.sockets[a_sock]['local_ip'], model.sockets[a_sock]['local_port']) 
    337  
    338     print "TCP server socket %s%d" % a_sock, "(private address " + local_addr + ") has", 
    339     print len(pending), "unaccepted connection(s)" 
    340     for trace_id, ip, port in pending_dict: 
    341       print " * There are", pending_dict[(trace_id, ip, port)], "unaccepted connection(s) from trace", 
    342       print trace_id, "to", format_addr(ip, port) 
    343  
    344     if a_sock in accept_dict: 
    345       print " * This server socket ignored connections from these IPs:", ", ".join(accept_dict[a_sock]) 
    346       print " * The traces whose connections have not been accepted may be behind NATs" 
    347       possible_nats = True 
    348     else: 
    349       errors.append("[Possible Network Misbehavior] Connections intended for the socket in trace " + 
    350            str(a_sock[0]) + " listening on "  + local_addr + " may have been accepted elsewhere") 
    351       if parsing_failed: 
    352         print " * Since the traces could not be fully processed, this alone may not be significant" 
    353       print " * The connecting sockets may have connected to an entirely different server socket" 
    354  
    355   ignored_accepts = [syscall for syscall, err in exception_list 
    356                      if err.args[1] == 'NO_PENDING_CONN' and syscall[2][0] != -1] 
    357  
    358   if ignored_accepts: 
    359     print 
    360     if not found_something: 
    361       print "-" * 80 
    362       print "Network Configuration Issues" 
    363       print "-" * 80 
    364     possible_nats = True 
    365     found_something = True 
    366  
    367   ignored_accept_dict = {} 
    368   for name, args, ret in ignored_accepts: 
    369     ignored_accept_dict.setdefault(args[:2], []).append(args[2]) 
    370  
    371   for a_sock in ignored_accept_dict: 
    372     local_addr = format_addr(model.sockets[a_sock]['local_ip'], model.sockets[a_sock]['local_port']) 
    373     print "TCP server socket %s%d (private address" % a_sock, 
    374     print local_addr + ") failed to find corresponding connects for", 
    375     print len(ignored_accept_dict[a_sock]), "accept(s)" 
    376  
    377     ignored_ip_dict = {} 
    378     for ip in ignored_accept_dict[a_sock]: 
    379       ignored_ip_dict.setdefault(ip, 0) 
    380       ignored_ip_dict[ip] += 1 
    381  
    382     for ip in ignored_ip_dict: 
    383       print " * There are", ignored_ip_dict[ip], "unmatched accepts from IP", ip 
    384  
    385     print " * Trace", a_sock[0], "may be behind a NAT and port forwarding may be occurring" 
    386  
    387   unknown_connect_failures = [syscall for syscall, err in exception_list 
    388                               if err.args[1] == 'UNEXPECTED_FAILURE' and 
    389                                  syscall[0] == 'connect_syscall'] 
    390  
    391   if unknown_connect_failures: 
    392     print 
    393     if not found_something: 
    394       print "-" * 80 
    395       print "Network Configuration Issues" 
    396       print "-" * 80 
    397     found_something = True 
    398     errors.append("[Possible Network Misbehavior] One or more connects failed with an unknown error. " + \ 
    399                   "This may be due to something filtering connection, for example a firewall.") 
    400  
    401   unknown_connect_dict = {} 
    402   for name, args, ret in unknown_connect_failures: 
    403     trace, sock, ip, port = args 
    404     connect_tuple = (trace, (ip, port)) 
    405     unknown_connect_dict.setdefault(connect_tuple, 0) 
    406     unknown_connect_dict[connect_tuple] += 1 
    407  
    408   for trace, connect_addr in unknown_connect_dict: 
    409     print "Trace", trace, "failed to connect to", format_addr(connect_addr[0], connect_addr[1]), 
    410     print unknown_connect_dict[(trace, connect_addr)], "time(s) with an unknown error" 
    411     for a_sock in model.sockets: 
    412       if model.sockets[a_sock]['state'] != 'LISTEN': 
    413         continue 
    414       ip = model.sockets[a_sock]['local_ip'] 
    415       port = model.sockets[a_sock]['local_port'] 
    416       is_match, warnings = is_addr_match(a_sock[0], (ip, port), trace, connect_addr, True) 
    417       if is_match: 
    418         print "   This address matches server socket %s%d, which was bound to" % a_sock, format_addr(ip, port) 
    419         for warning in warnings: 
    420           print "    * [Warning]", warning 
    421  
    422   refused_connect_failures = [syscall for syscall, err in exception_list 
    423                               if err.args[1] == 'ECONNREFUSED' and 
    424                                  syscall[0] == 'connect_syscall'] 
    425  
    426   if refused_connect_failures: 
    427     print 
    428     if not found_something: 
    429       print "-" * 80 
    430       print "Network Configuration Issues" 
    431       print "-" * 80 
    432     found_something = True 
    433  
    434   refused_connect_dict = {} 
    435   for name, args, ret in refused_connect_failures: 
    436     trace, sock, ip, port = args 
    437     connect_tuple = (trace, (ip, port)) 
    438     refused_connect_dict.setdefault(connect_tuple, 0) 
    439     refused_connect_dict[connect_tuple] += 1 
    440  
    441   refused_issue = False 
    442  
    443   for trace, connect_addr in refused_connect_dict: 
    444     print "Trace", trace, "failed to connect to", format_addr(connect_addr[0], connect_addr[1]), 
    445     print refused_connect_dict[(trace, connect_addr)], "time(s) because the connection was refused" 
    446     for a_sock in model.sockets: 
    447       if model.sockets[a_sock]['state'] != 'LISTEN': 
    448         continue 
    449       ip = model.sockets[a_sock]['local_ip'] 
    450       port = model.sockets[a_sock]['local_port'] 
    451       is_match, warnings = is_addr_match(a_sock[0], (ip, port), trace, connect_addr, True) 
    452       if is_match: 
    453         refused_issue = True 
    454         print "   This address matches server socket %s%d, which was bound to" % a_sock, format_addr(ip, port) 
    455         for warning in warnings: 
    456           print "    * [Warning]", warning 
    457  
    458   if refused_issue: 
    459     errors.append("[Ambiguous Misbehavior] One or more connects to addresses that were being listened on failed. " + \ 
    460                   "This may be due to the timing of the connect and listen or may be due to a network issue.") 
    461  
    462   failed_nonblock_connects = {} 
    463  
    464   for sock in model.sockets: 
    465     if model.sockets[sock]['state'] == 'PENDING' and \ 
    466         not addr_dont_care(model.sockets[sock]['peer_ip'], model.sockets[sock]['peer_port']): 
    467       connect_tuple = (sock[0], model.sockets[sock]['peer_ip'], model.sockets[sock]['peer_port']) 
    468       failed_nonblock_connects.setdefault(connect_tuple, 0) 
    469       failed_nonblock_connects[connect_tuple] += 1 
    470  
    471   if failed_nonblock_connects: 
    472     print 
    473     if not found_something: 
    474       print "-" * 80 
    475       print "Network Configuration Issues" 
    476       print "-" * 80 
    477     found_something = True 
    478     print "Several nonblocking connects may have failed to connect" 
    479     for trace, ip, port in failed_nonblock_connects: 
    480       number = failed_nonblock_connects[(trace, ip, port)] 
    481       print " *", number, "nonblocking connects from trace", trace, "to", 
    482       print format_addr(ip, port), "were never observed to connect" 
    483  
    484   no_traffic = [trace_id for trace_id in trace_has_traffic 
    485                 if has_dontcare_traffic[trace_id] and not trace_has_traffic[trace_id]] 
    486  
    487   if no_traffic and not found_something: 
    488     print 
    489     print "-" * 80 
    490     print "Network Configuration Issues" 
    491     print "-" * 80 
    492     print "These traces have network activity, but do not appear to communicate with other traces:", ", ".join(no_traffic) 
    493     if parsing_failed: 
    494       print " * Since the traces could not be fully processed, this alone may not be significant" 
    495     print " * This may indicate that they are behind a NAT" 
    496     print " * It is also possible that there is a third party acting as a proxy or forwarding traffic" 
    497     possible_nats = True 
    498  
    499   if possible_nats: 
    500     errors.append("There may be one or more NATs not declared in the configuration file") 
    501     print 
    502     print "Please check if there are any NATs present which are not explicitly declared in the configuration file" 
    503     print " * If so, add them to configuration file and rerun NetCheck" 
    504  
    505   return errors 
    506  
    507  
    508 def check_exceptions(): 
    509  
    510   unknown_calls = set() 
    511   buffer_size_exceptions = {} 
    512   option_not_handled_exceptions = 0 
    513   overlapping_conns = set() 
    514  
    515   connect_failed = [] 
    516  
    517   for syscall, err in exception_list: 
    518     name, args, ret = syscall 
    519     trace_id = args[0] 
    520     impl_ret, impl_err = ret 
    521     model_err = err.args[1] 
    522  
    523     if model_err == 'UNKNOWN_SYSCALL': 
    524       unknown_calls.add(name) 
    525     elif model_err == 'NOT_HANDLE_OPTION' or model_err == 'UNKNOWN_LEVEL': 
    526       option_not_handled_exceptions += 1 
    527     elif model_err == 'MSG_>_BUFSIZE': 
    528       buffer_size_exceptions.setdefault(trace_id, 0) 
    529       buffer_size_exceptions[trace_id] += 1 
    530     elif model_err == 'OVERLAPPING_CONNECTS': 
    531       overlapping_conns.add(trace_id) 
    532     elif model_err == 'UNEXPECTED_SUCCESS': 
    533       if name == 'connect_syscall': 
    534         trace_id, sock, ip, port = args 
    535         connect_failed.append((trace_id, ip, port, impl_err)) 
    536  
    537   errors = [] 
    538  
    539   for trace_id in buffer_size_exceptions: 
    540     errors.append("[Possible Network Misbehavior] " + str(buffer_size_exceptions[trace_id]) + 
    541         " different call(s) caused trace " + str(trace_id) + " to exceeded an expected buffer size") 
    542  
    543   for trace_id, ip, port, impl_err in connect_failed: 
    544     errors.append("[Possible Network Misbehavior] Trace " + trace_id + " unexpectedly failed to connect to " 
    545          + format_addr(ip, port) + " with the following error: " + impl_err) 
    546  
    547   if unknown_calls: 
    548     errors.append("The following call(s) are not currently handled by the model: " + ", ".join(unknown_calls)) 
    549  
    550   if option_not_handled_exceptions: 
    551     errors.append(str(option_not_handled_exceptions) + 
    552         " call(s) to getsockopt, setsockopt, fcntl, or ioctl used options which are not currently handled") 
    553  
    554   if overlapping_conns: 
    555     if len(overlapping_conns) == 1: 
    556       errors.append("Trace " + list(overlapping_conns)[0] + 
    557           " has simultaneously occurring nonblocking connects, which may " + 
    558           "mean that the corresponding accepts are improperly matched") 
    559     else: 
    560       errors.append("Trace(s) " + ", ".join(overlapping_conns) + 
    561           " have simultaneously occurring nonblocking connects, which may " + 
    562           "mean that the corresponding accepts are improperly matched") 
    563  
    564   return errors 
    565  
    566  
    567 def check_tcp_buffers(): 
    568  
    569   for t in model.tcp_tuples: 
    570     if t['accepting_fd'] is not None: 
    571       break 
    572   else: 
    573     return [] 
    574  
    575   if PRINT_STATISTICS: 
    576     print 
    577     print "-" * 80 
    578     print "TCP Connection Statistics" 
    579     print "-" * 80 
    580  
    581   nonempty_connection_dict = {} 
    582  
    583   poll_errors = set([syscall[1][:2] for syscall, err in exception_list 
    584                      if (err.args[0] == 'recv_syscall' or err.args[0] == 'send_syscall') and 
    585                         err.args[1].startswith('NETWORK_ERROR')]) 
    586  
    587   for t in model.tcp_tuples: 
    588     # Connection was never accepted 
    589     if t['accepting_fd'] is None: 
    590       continue  
    591  
    592     connect_sock = model.sockets[t['connected_fd']] 
    593     accept_sock = model.sockets[t['accepting_fd']] 
    594     connect_tuple = (t['connected_fd'][0], connect_sock['peer_ip'], connect_sock['peer_port']) 
    595  
    596     if t['c_buffer'][1] != 0 or t['a_buffer'][1] != 0: 
    597       event_tuple = connect_tuple + (t['connected_fd'] in poll_errors or 
    598           t['accepting_fd'] in poll_errors,) 
    599       nonempty_connection_dict.setdefault(event_tuple, 0) 
    600       nonempty_connection_dict[event_tuple] += 1 
    601  
    602     if PRINT_STATISTICS: 
    603       print "Connection from socket %s%d (public address" % t['connected_fd'], 
    604       print format_addr(accept_sock['peer_ip'], accept_sock['peer_port']) + ")", 
    605       print "to socket %s%d (public address" % t['accepting_fd'], 
    606       print format_addr(connect_sock['peer_ip'], connect_sock['peer_port']) + ")" 
    607  
    608       print " * Data sent to accepting socket %s%d:" % t['accepting_fd'], 
    609       print t['c_buffer'][2], "bytes sent,", 
    610       print t['c_buffer'][2] - t['c_buffer'][1], "bytes received,", 
    611       print t['c_buffer'][1], "bytes lost", 
    612       if t['c_buffer'][1]: 
    613         print "(%.2f%%)" % (100.0 * t['c_buffer'][1] / t['c_buffer'][2]), 
    614       print 
    615  
    616       print " * Data sent to connected socket %s%d:" % t['connected_fd'], 
    617       print t['a_buffer'][2], "bytes sent,", 
    618       print t['a_buffer'][2] - t['a_buffer'][1], "bytes received,", 
    619       print t['a_buffer'][1], "bytes lost", 
    620       if t['a_buffer'][1]: 
    621         print "(%.2f%%)" % (100.0 * t['a_buffer'][1] / t['a_buffer'][2]), 
    622       print 
    623  
    624       if t['c_buffer'][1] != 0 or t['a_buffer'][1] != 0: 
    625         if t['connected_fd'] in poll_errors or t['accepting_fd'] in poll_errors: 
    626           print " * [Ambiguous Misbehavior] Data loss may be due to network conditions, such as filtering or network delay, but may also be due to delay in application itself" 
    627         else: 
    628           print " * [Possible Application Misbehavior] Data loss is most likely due to application behavior" 
    629  
    630       if t['connected_fd'] in send_after_closed_dict: 
    631         print " * [Possible Application Misbehavior] socket %s%d" % t['connected_fd'], 
    632         print "failed to send some data because the connection was closed" 
    633  
    634       if t['accepting_fd'] in send_after_closed_dict: 
    635         print " * [Possible Application Misbehavior] socket %s%d" % t['accepting_fd'], 
    636         print "failed to send some data because the connection was closed" 
    637  
    638   errors = [] 
    639  
    640   for trace_id, ip, port, is_ambiguous in nonempty_connection_dict: 
    641     if is_ambiguous: 
    642       errors.append("[Ambiguous Misbehavior] Trace " + trace_id + " has " + 
    643           str(nonempty_connection_dict[(trace_id, ip, port, is_ambiguous)]) + " TCP connection(s) to " + 
    644           format_addr(ip, port) + " with unreceived data not detected by poll or select") 
    645     else: 
    646       errors.append("[Possible Application Misbehavior] Trace " + trace_id + " has " + 
    647           str(nonempty_connection_dict[(trace_id, ip, port, is_ambiguous)]) + " TCP connection(s) to " + 
    648           format_addr(ip, port) + " with data left in the buffers") 
    649  
    650   return errors 
    651  
    652  
    653 def check_udp_buffers(): 
    654  
    655   if not model.udp_tuples: 
    656     return [] 
    657  
    658   connection_dict = {} 
    659  
    660   for t in model.udp_tuples: 
    661     if t['connected_ip']: 
    662       sender = (t['connected_ip'], t['connected_port']) 
    663     else: 
    664       sender = list(t['connected_fd_list'])[0][0] 
    665     receiver = (t['accepting_ip'], t['accepting_port']) 
    666     connect_tuple = (sender, receiver) 
    667     accept_tuple = (receiver, sender) 
    668     if connect_tuple not in connection_dict: 
    669       connection_dict[connect_tuple] = {'sent': 0, 'lost': 0, 'bytes_sent': 0, 'bytes_lost': 0} 
    670     if accept_tuple not in connection_dict: 
    671       connection_dict[accept_tuple] = {'sent': 0, 'lost': 0, 'bytes_sent': 0, 'bytes_lost': 0} 
    672  
    673     for m in t['a_dtgrams']: 
    674       connection_dict[accept_tuple]['sent'] += t['a_dtgrams'][m][0] 
    675       connection_dict[accept_tuple]['bytes_sent'] += t['a_dtgrams'][m][0] * len(m) 
    676       unreceived = t['a_dtgrams'][m][0] - t['a_dtgrams'][m][1] 
    677       if unreceived > 0: 
    678         connection_dict[accept_tuple]['lost'] += unreceived 
    679         connection_dict[accept_tuple]['bytes_lost'] += unreceived * len(m) 
    680  
    681     for m in t['c_dtgrams']: 
    682       connection_dict[connect_tuple]['sent'] += t['c_dtgrams'][m][0] 
    683       connection_dict[connect_tuple]['bytes_sent'] += t['c_dtgrams'][m][0] * len(m) 
    684       unreceived = t['c_dtgrams'][m][0] - t['c_dtgrams'][m][1] 
    685       if unreceived > 0: 
    686         connection_dict[connect_tuple]['lost'] += unreceived 
    687         connection_dict[connect_tuple]['bytes_lost'] += unreceived * len(m) 
    688  
    689   errors = [] 
    690  
    691   if PRINT_STATISTICS: 
    692     print 
    693     print "-" * 80 
    694     print "UDP Traffic Statistics" 
    695     print "-" * 80 
    696  
    697     for sender, receiver in connection_dict: 
    698       addr_dict = connection_dict[(sender, receiver)] 
    699  
    700       if not addr_dict['sent']: 
    701         continue 
    702  
    703       if isinstance(sender, tuple): 
    704         sender_str = format_addr(sender[0], sender[1]) 
    705       else: 
    706         sender_str = "trace " + sender 
    707       receiver_str = format_addr(receiver[0], receiver[1]) 
    708  
    709       print "Traffic from", sender_str, "to", receiver_str 
    710  
    711       print " *", 
    712       print addr_dict['sent'], "datagrams sent,", 
    713       print addr_dict['sent'] - addr_dict['lost'], "datagrams received,", 
    714       print addr_dict['lost'], "datagrams lost", 
    715       if addr_dict['lost']: 
    716         print "(%.2f%%)" % (100.0 * addr_dict['lost'] / addr_dict['sent']), 
    717       print 
    718  
    719       print " *", 
    720       print addr_dict['bytes_sent'], "bytes sent,", 
    721       print addr_dict['bytes_sent'] - addr_dict['bytes_lost'], "bytes received,", 
    722       print addr_dict['bytes_lost'], "bytes lost", 
    723       if addr_dict['bytes_lost']: 
    724         print "(%.2f%%)" % (100.0 * addr_dict['bytes_lost'] / addr_dict['bytes_sent']), 
    725       print 
    726  
    727       if addr_dict['lost'] == addr_dict['sent']: 
    728         errors.append("[Possible Network Misbehavior] All " + str(addr_dict['sent']) + 
    729             " datagrams sent from " + sender_str + " to " + receiver_str + " were lost") 
    730  
    731   return errors 
    732  
    733  
    734 def print_model_state(): 
    735   if PRINT_MODEL_STATE: 
    736     print 
    737     print "-" * 80 
    738     print "Final Model State" 
    739     print "-" * 80 
    740     print "tcp_tuples:" 
    741     for t in model.tcp_tuples: 
    742       print "  ", t 
    743  
    744     print 
    745     print "udp_tuples:" 
    746     for t in model.udp_tuples: 
    747       print "  ", t 
    748  
    749     print 
    750     print "sockets:" 
    751     for socket in model.sockets: 
    752       print "  ", 
    753       if socket in model.active_sockets: 
    754         print "[ACTIVE]", 
    755       print str(socket) + ":", model.sockets[socket] 
    756  
    757     print 
    758     print "pending_connections:", model.pending_connections 
    759     print "poll_timeout:", list(model.poll_timeout) 
Note: See TracChangeset for help on using the changeset viewer.