示例#1
0
    def add_flow(self, link, id, f_tuple, m_tuple):
        """ 
        We have a newly reported flow from a client.  Ensure that the
        proper data structures are in place for it.  In this instance we
        assume that either end could be firewalled.  
        """

        # This is a bit tricky.  First, we adopt the convention that Alice is
        # always the sender for a flow, and Bob the receiver (so for a TCP
        # session, each end is Alice in one direction and Bob in the other).

        # Next, observe that both Alice and Bob will send "active-flows"
        # messages adding the flow.  Those might arrive in either order.
        # Furthermore, Bob might send an "active-flows", then a whole lot of
        # "recv"s, long before Alice sends her "active-flow" -- so whichever end
        # sends first needs to trigger the instantiation of the Flows and the
        # Reconciliator.

        # XXX There are some nasty special cases we don't currently handle here:
        # 1. The first packet in a flow is mangled in transit, so the
        # opening_hashes don't match.  The port numbers will sometimes tip us of
        # to this
        # 2. The first packet in a flow does not arrive first.  This shouldn't
        # be possible for TCP, but it may well happen with other protocols.

        f = f_tuple
        self.global_flow_lock.acquire()
        try:
            if m_tuple not in self.flow_matchmaker:

                errlog.info("Creating flow: %s" % ` print_flow_tuple(f) `)
                rec = Reconciliator.Reconciliator(f, m_tuple)
                rec.add_link(link, id, f)  # it'll figure out which side we are

                self.flow_matchmaker[m_tuple] = rec
                errlog.debug("Matchmaker is now %s" % ` self.flow_matchmaker `)
            else:
                rec = self.flow_matchmaker[m_tuple]
                if rec.add_link(link, id, f):
                    # we have two sides to this flow now
                    if self.config.logging:
                        self.log.new_flow(print_flow_tuple(f_tuple), rec.id)
        finally:
            self.global_flow_lock.release()

        # now register the flow in the link itself
        link.flow_lock.acquire()
        try:
            link.flow_table[id] = (f_tuple, rec)
        finally:
            link.flow_lock.release()
示例#2
0
    def add_flow(self, link, id, f_tuple, m_tuple):
        """ 
        We have a newly reported flow from a client.  Ensure that the
        proper data structures are in place for it.  In this instance we
        assume that either end could be firewalled.  
        """

        # This is a bit tricky.  First, we adopt the convention that Alice is
        # always the sender for a flow, and Bob the receiver (so for a TCP
        # session, each end is Alice in one direction and Bob in the other).

        # Next, observe that both Alice and Bob will send "active-flows"
        # messages adding the flow.  Those might arrive in either order.
        # Furthermore, Bob might send an "active-flows", then a whole lot of
        # "recv"s, long before Alice sends her "active-flow" -- so whichever end
        # sends first needs to trigger the instantiation of the Flows and the
        # Reconciliator.  
        
        # XXX There are some nasty special cases we don't currently handle here:
        # 1. The first packet in a flow is mangled in transit, so the
        # opening_hashes don't match.  The port numbers will sometimes tip us of
        # to this
        # 2. The first packet in a flow does not arrive first.  This shouldn't
        # be possible for TCP, but it may well happen with other protocols.

        f = f_tuple
        self.global_flow_lock.acquire()
        try:
          if m_tuple not in self.flow_matchmaker:
     
            errlog.info("Creating flow: %s" % `print_flow_tuple(f)`)
            rec = Reconciliator.Reconciliator(f,m_tuple)
            rec.add_link(link, id, f)        # it'll figure out which side we are

            self.flow_matchmaker[m_tuple] = rec
            errlog.debug("Matchmaker is now %s" % `self.flow_matchmaker`)
          else:
            rec = self.flow_matchmaker[m_tuple]
            if rec.add_link(link, id, f):
              # we have two sides to this flow now
              if self.config.logging: 
                self.log.new_flow(print_flow_tuple(f_tuple), rec.id)
        finally:
          self.global_flow_lock.release()
        
        # now register the flow in the link itself
        link.flow_lock.acquire()
        try:
          link.flow_table[id] = (f_tuple, rec)
        finally:
          link.flow_lock.release()
示例#3
0
  def ponder_flow(self, link, alice_id, f_tuple, opening_hash):
    """
    Sanity check before we allow a flow into our data structures.
    If yes, return a representation of the flow for our matchmaker.
    If no, return False.
    """

    # XXX decide whether to add promiscuity here
    self.peer_lock.acquire()
    try:
      self.debug_note("IS THIS RELEVANT to %s? %s %s" % (link.peer[0], 
      `print_flow_tuple(f_tuple)`, `self.peer_ips.keys()`), seriousness=-1)

      # link_ip is the ip we expect to find for this client inside its flows
      # match_ip is the ip we want to use for matchmaking

      match_ip = s.inet_aton(link.peer[0])
      if link.alice_firewalled:
        self.debug_note("..firewalled..", seriousness=-1)
        link_ip = link.peers_private_ip
      else:
        self.debug_note("..not firewalled..%s" % \
          `link.alice_firewalled`, seriousness=-1)
        link_ip  = link.peer[0]
      assert s.inet_aton(link_ip)

      self.debug_note("link and match: %s %s" % 
                      (link_ip,`match_ip`), seriousness=-1)

      ip1bin = f_tuple[FlowTuple.src_ip]
      ip1 = s.inet_ntoa(ip1bin)
      ip2bin = f_tuple[FlowTuple.dest_ip]
      ip2 = s.inet_ntoa(ip2bin)

      if ip1 == link_ip and ip2 in self.peer_ips:
        return (match_ip, ip2bin, opening_hash)
      if ip2 == link_ip and ip1 in self.peer_ips:
        return (ip1bin, match_ip, opening_hash)

    finally:
      self.peer_lock.release()
    link.flow_lock.acquire()
    try:
      link.flow_table[alice_id] = None
    finally:
      link.flow_lock.release()
    return False
示例#4
0
    def add_link(self, link, id, f_tuple):
        "Figure out whether this link is alice or bob, and remember it"
        if f_tuple == None:
            log.error("add_link should not be called with f_tuple=None!!!!")
            return False
        self.lock.acquire()
        try:
            ip = s.inet_aton(link.peer[0])

            if ip == self.m_tuple[0]:
                self.src_links.append((link, id))
                self.src_flow = f_tuple
                if len(self.src_links) != 1:
                    link.debug_note("Duplicate src_links: %s" %
                                    ` self.src_links `)
            elif ip == self.m_tuple[1]:
                self.dest_links.append((link, id))
                self.dest_flow = f_tuple
                if len(self.dest_links) != 1:
                    link.debug_note("Duplicate dest_links: %s" %
                                    ` self.dest_links `)
            else:
                link.protocol_error(
                    "Argh, confused about links and reconciliators!\n")

            if self.dest_links and self.src_links:

                skew1 = max(
                    [l.get_clock_dispersion() for l, id in self.src_links])
                skew2 = max(
                    [l.get_clock_dispersion() for l, id in self.dest_links])
                self.max_clock_skew = (skew1 + skew2) + clock_safety_margin
                if not (self.src_flow and self.dest_flow):
                    # This is debugging for "weird error"s
                    log.error("Was about to ready a one-sided flow!!!")
                    return False
                self.ready = True
                log.debug("We now have both sides of flow %s",
                          print_flow_tuple(self.flow))
                return True  # have both sides
            else:
                log.debug("We currently only have one side of flow: %s",
                          print_flow_tuple(self.flow))
                return False
        finally:
            self.lock.release()
  def add_link(self, link, id, f_tuple):
    "Figure out whether this link is alice or bob, and remember it"
    if f_tuple == None:
      log.error("add_link should not be called with f_tuple=None!!!!")
      return False
    self.lock.acquire()
    try:
      ip = s.inet_aton(link.peer[0])

      if ip == self.m_tuple[0]:
        self.src_links.append((link, id))
        self.src_flow = f_tuple
        if len(self.src_links) != 1:
          link.debug_note("Duplicate src_links: %s" % `self.src_links`)
      elif ip == self.m_tuple[1]:
        self.dest_links.append((link, id))
        self.dest_flow = f_tuple
        if len(self.dest_links) != 1:
          link.debug_note("Duplicate dest_links: %s" % `self.dest_links`)
      else:
        link.protocol_error("Argh, confused about links and reconciliators!\n")

      if self.dest_links and self.src_links:
        
        skew1 = max([l.get_clock_dispersion() for l,id in self.src_links])
        skew2 = max([l.get_clock_dispersion() for l,id in self.dest_links])
        self.max_clock_skew = (skew1 + skew2) + clock_safety_margin
        if not (self.src_flow and self.dest_flow):
          # This is debugging for "weird error"s
          log.error("Was about to ready a one-sided flow!!!")
          return False
        self.ready = True
        log.debug("We now have both sides of flow %s", print_flow_tuple(self.flow))
        return True # have both sides
      else:
        log.debug("We currently only have one side of flow: %s", print_flow_tuple(self.flow))
        return False
    finally:
      self.lock.release()
示例#6
0
  def handle_sent_or_recd(self, link, args, sent):
    """
    Sent and recd messages are conceptually very similar, so this function
    handles both cases.  sent = True|False accordingly.
    """
    flow_id, timestamp, hashes = args
    link.flow_lock.acquire()
    try:
      entry = link.flow_table[flow_id]
    finally:
      link.flow_lock.release()

    if entry:
      rec = entry[1]
    else:
      # This flow is being ignored because it isn't between our peers
      return False
    rec.lock.acquire()
    try:
      try:
        if sent:
          forgeries = rec.sent_by_alice(timestamp, hashes)
          drops = rec.check_for_drops()
          if drops:
            self.debug_note("%d dropped packets!" % len(drops))
        else:
          forgeries = rec.recd_by_bob(timestamp, hashes)
      except Reconciliator.Dangling:
        opening_hash = rec.m_tuple[2]
        link.send_message("dangling-flow", [flow_id, opening_hash])
        log.warn("Flow %s is dangling" % `print_flow_tuple(rec.flow)`)
        link.flow_lock.acquire()
        try:
          link.flow_table[flow_id] = None
        finally:
          link.flow_lock.release()
        return
      except AssertionError:
        # Various things could cause this...
        link.protocol_error("Assertion violated while handling sent/recd\n" +\
                            traceback.format_exc())
        raise
    finally:
      rec.lock.release()
    if forgeries:
      self.spotted_forgeries(forgeries, rec)
    if sent: s = "+"
    else: s = "-"
    if self.config.seriousness_threshold <=0:
      sys.stdout.write(s)
      sys.stdout.flush()
示例#7
0
  def handle_active_flows(self, link, args):
    "The active_flows message from Alice updates our state of flows."
    new_flows, deleted_flows = args

    # Process deleted flows first, because we might want to delete a flow
    # and recreate it simultaneously if it has been closed and re-SYNed

    try:
      if not self.config.keep_reconciliators:
        self.debug_note("deleting flows: %s" % deleted_flows)
        for f_id in deleted_flows:
          self.mm.delete_flow(link, f_id)
    except:
      link.protocol_error("Problem with flow list: %s\n" % 
                                              util.screensafe(new_flows))
      raise

    # Now the new flows:
    try:
      for flow in new_flows:
        f_id = flow[0]
        assert len(flow[1]) == Protocol.hash_length, \
               "hashlen is not %d in %r" % (Protocol.hash_length, flow)
        if ipids_in_matchmaker:
          opening_hash = flow[1]
        else:
          opening_hash = flow[1][:-2]
        f_tuple = flow[2]
        assert len(f_tuple) == 5
        assert type(opening_hash) == str

        match = self.ponder_flow(link, f_id, f_tuple, opening_hash)
        if match:
          self.debug_note("YES", seriousness=-1)
          self.mm.add_flow(link, f_id, f_tuple, match)
        else:
          self.debug_note("NO", seriousness=-1)
          if not self.config.sloppy:
            self.debug_note("Mysteriously Irrelevant Flow!!!%s" %
                            `(link.peer[0],print_flow_tuple(f_tuple))`)

    except:
      errlog.debug("OH NOES %s", traceback.format_exc())
      link.protocol_error("Problem with flow list: %s\n" % 
                                            util.screensafe(new_flows))
      raise
示例#8
0
def flow_key(f):
    t = print_flow_tuple(f.flow_tuple)
            
    return str(t[0].replace(".","_")) + "_" + str(t[1]) + "__" \
        + str(t[2].replace(".","_")) + "_" + str((t[3])) \
        + "_" + str(t[4])