Пример #1
0
def _ParseMsgControl(buf):
    """Parse a raw control buffer into a list of tuples."""
    msglist = []
    while len(buf) > 0:
        cmsghdr, buf = cstruct.Read(buf, CMsgHdr)
        datalen = cmsghdr.len - len(CMsgHdr)
        data, buf = buf[:datalen], buf[PaddedLength(datalen):]

        if cmsghdr.level == socket.IPPROTO_IP:
            if cmsghdr.type == IP_PKTINFO:
                data = InPktinfo(data)
            elif cmsghdr.type == IP_TTL:
                data = struct.unpack("@I", data)[0]

        if cmsghdr.level == socket.IPPROTO_IPV6:
            if cmsghdr.type == IPV6_PKTINFO:
                data = In6Pktinfo(data)
            elif cmsghdr.type == IPV6_RECVERR:
                err, source = cstruct.Read(data, SockExtendedErr)
                if err.origin == SO_ORIGIN_ICMP6:
                    source, pad = cstruct.Read(source, SockaddrIn6)
                data = (err, source)
            elif cmsghdr.type == IPV6_HOPLIMIT:
                data = struct.unpack("@I", data)[0]

        # If not, leave data as just the raw bytes.

        msglist.append((cmsghdr.level, cmsghdr.type, data))

    return msglist
Пример #2
0
  def DecodeBytecode(bytecode):
    instructions = []
    try:
      while bytecode:
        op, rest = cstruct.Read(bytecode, InetDiagBcOp)

        if op.code in [INET_DIAG_BC_NOP, INET_DIAG_BC_JMP, INET_DIAG_BC_AUTO]:
          arg = None
        elif op.code in [INET_DIAG_BC_S_GE, INET_DIAG_BC_S_LE,
                         INET_DIAG_BC_D_GE, INET_DIAG_BC_D_LE]:
          op, rest = cstruct.Read(rest, InetDiagBcOp)
          arg = op.no
        elif op.code in [INET_DIAG_BC_S_COND, INET_DIAG_BC_D_COND]:
          cond, rest = cstruct.Read(rest, InetDiagHostcond)
          if cond.family == 0:
            arg = (None, cond.prefix_len, cond.port)
          else:
            addrlen = 4 if cond.family == AF_INET else 16
            addr, rest = rest[:addrlen], rest[addrlen:]
            addr = inet_ntop(cond.family, addr)
            arg = (addr, cond.prefix_len, cond.port)
        elif op.code == INET_DIAG_BC_DEV_COND:
          attrlen = struct.calcsize("=I")
          attr, rest = rest[:attrlen], rest[attrlen:]
          arg = struct.unpack("=I", attr)
        elif op.code == INET_DIAG_BC_MARK_COND:
          arg, rest = cstruct.Read(rest, InetDiagMarkcond)
        else:
          raise ValueError("Unknown opcode %d" % op.code)
        instructions.append((op, arg))
        bytecode = rest

      return instructions
    except (TypeError, ValueError):
      return "???"
Пример #3
0
    def _Decode(self, command, unused_msg, nla_type, nla_data):
        """Decodes netlink attributes to Python types."""
        name = self._GetConstantName(nla_type, "XFRMA_")

        if name in ["XFRMA_ALG_CRYPT", "XFRMA_ALG_AUTH"]:
            data = cstruct.Read(nla_data, XfrmAlgo)[0]
        elif name == "XFRMA_ALG_AUTH_TRUNC":
            data = cstruct.Read(nla_data, XfrmAlgoAuth)[0]
        elif name == "XFRMA_ENCAP":
            data = cstruct.Read(nla_data, XfrmEncapTmpl)[0]
        else:
            data = nla_data

        return name, data
Пример #4
0
def ParseExtension(exttype, data):
  struct_type = None
  if exttype == SADB_EXT_SA:
    struct_type = SadbSa
  elif exttype in [SADB_EXT_LIFETIME_CURRENT, SADB_EXT_LIFETIME_HARD,
                   SADB_EXT_LIFETIME_SOFT]:
    struct_type = SadbLifetime
  elif exttype in [SADB_EXT_ADDRESS_SRC, SADB_EXT_ADDRESS_DST,
                   SADB_EXT_ADDRESS_PROXY]:
    struct_type = SadbAddress
  elif exttype in [SADB_EXT_KEY_AUTH, SADB_EXT_KEY_ENCRYPT]:
    struct_type = SadbKey
  elif exttype == SADB_X_EXT_SA2:
    struct_type = SadbXSa2
  elif exttype == SADB_X_EXT_NAT_T_TYPE:
    struct_type = SadbXNatTType
  elif exttype in [SADB_X_EXT_NAT_T_SPORT, SADB_X_EXT_NAT_T_DPORT]:
    struct_type = SadbXNatTPort

  if struct_type:
    ext, attrs = cstruct.Read(data, struct_type)
  else:
    ext, attrs, = data, ""

  return exttype, ext, attrs
Пример #5
0
  def _ExpectEspPacketOn(self, netid, spi, seq, length, src_addr, dst_addr):
    """Read a packet from a netid and verify its properties.

    Args:
      netid: netid from which to read an ESP packet
      spi: SPI of the ESP packet in host byte order
      seq: sequence number of the ESP packet
      length: length of the packet's ESP payload or None to skip this check
      src_addr: source address of the packet or None to skip this check
      dst_addr: destination address of the packet or None to skip this check

    Returns:
      scapy.IP/IPv6: the read packet
    """
    packets = self.ReadAllPacketsOn(netid)
    self.assertEquals(1, len(packets))
    packet = packets[0]
    if length is not None:
      self.assertEquals(length, len(packet.payload))
    if dst_addr is not None:
      self.assertEquals(dst_addr, packet.dst)
    if src_addr is not None:
      self.assertEquals(src_addr, packet.src)
    # extract the ESP header
    esp_hdr, _ = cstruct.Read(str(packet.payload), xfrm.EspHdr)
    self.assertEquals(xfrm.EspHdr((spi, seq)), esp_hdr)
    return packet
Пример #6
0
  def AllocSpi(self, dst, proto, min_spi, max_spi):
    """Allocate (reserve) an SPI.

    This sends an XFRM_MSG_ALLOCSPI message and returns the resulting
    XfrmUsersaInfo struct.

    Args:
      dst: A string, the destination IP address. Forms part of the XFRM ID, and
        must match the destination address of the packets sent by this SA.
      proto: the protocol DB of the SA, such as IPPROTO_ESP.
      min_spi: The minimum value of the acceptable SPI range (inclusive).
      max_spi: The maximum value of the acceptable SPI range (inclusive).
    """
    spi = XfrmUserSpiInfo("\x00" * len(XfrmUserSpiInfo))
    spi.min = min_spi
    spi.max = max_spi
    spi.info.id.daddr = PaddedAddress(dst)
    spi.info.id.proto = proto
    spi.info.family = AF_INET6 if ":" in dst else AF_INET

    msg = spi.Pack()
    flags = netlink.NLM_F_REQUEST
    self._SendNlRequest(XFRM_MSG_ALLOCSPI, msg, flags)
    # Read the response message.
    data = self._Recv()
    nl_hdr, data = cstruct.Read(data, netlink.NLMsgHdr)
    if nl_hdr.type == XFRM_MSG_NEWSA:
      return XfrmUsersaInfo(data)
    if nl_hdr.type == netlink.NLMSG_ERROR:
      error = netlink.NLMsgErr(data).error
      raise IOError(error, os.strerror(-error))
    raise ValueError("Unexpected netlink message type: %d" % nl_hdr.type)
Пример #7
0
 def ParseExtensions(data):
   """Parses the extensions in a SADB message."""
   extensions = []
   while data:
     ext, data = cstruct.Read(data, SadbExt)
     datalen = PfKey.ExtensionsLength(ext, SadbExt)
     extdata, data = data[:datalen], data[datalen:]
     extensions.append(ParseExtension(ext.exttype, extdata))
   return extensions
Пример #8
0
    def _ParseNLMsg(self, data, msgtype):
        """Parses a Netlink message into a header and a dictionary of attributes."""
        nlmsghdr, data = cstruct.Read(data, NLMsgHdr)
        self._Debug("  %s" % nlmsghdr)

        if nlmsghdr.type == NLMSG_ERROR or nlmsghdr.type == NLMSG_DONE:
            print "done"
            return (None, None), data

        nlmsg, data = cstruct.Read(data, msgtype)
        self._Debug("    %s" % nlmsg)

        # Parse the attributes in the nlmsg.
        attrlen = nlmsghdr.length - len(nlmsghdr) - len(nlmsg)
        attributes = self._ParseAttributes(nlmsghdr.type, nlmsg,
                                           data[:attrlen])
        data = data[attrlen:]
        return (nlmsg, attributes), data
Пример #9
0
 def _ParseAck(self, response):
     # Find the error code.
     hdr, data = cstruct.Read(response, NLMsgHdr)
     if hdr.type == NLMSG_ERROR:
         error = NLMsgErr(data).error
         if error:
             raise IOError(error, os.strerror(-error))
     else:
         raise ValueError("Expected ACK, got type %d" % hdr.type)
Пример #10
0
 def assertIsUdpEncapEsp(self, packet, spi, seq, length):
     self.assertEquals(IPPROTO_UDP, packet.proto)
     udp_hdr = packet[scapy.UDP]
     self.assertEquals(4500, udp_hdr.dport)
     self.assertEquals(length, len(udp_hdr))
     esp_hdr, _ = cstruct.Read(str(udp_hdr.payload), xfrm.EspHdr)
     # FIXME: this file currently swaps SPI byte order manually, so SPI needs to
     # be double-swapped here.
     self.assertEquals(xfrm.EspHdr((spi, seq)), esp_hdr)
Пример #11
0
    def _ReadNlAttr(self, data):
        # Read the nlattr header.
        nla, data = cstruct.Read(data, NLAttr)

        # Read the data.
        datalen = nla.nla_len - len(nla)
        padded_len = util.GetPadLength(NLA_ALIGNTO, datalen) + datalen
        nla_data, data = data[:datalen], data[padded_len:]

        return nla, nla_data, data
Пример #12
0
  def GetIfinfo(self, dev_name):
    """Fetches information about the specified interface.

    Args:
      dev_name: A string, the name of the interface.

    Returns:
      A tuple containing an IfinfoMsg struct and raw, undecoded attributes.
    """
    ifinfo = IfinfoMsg().Pack()
    ifinfo += self._NlAttrStr(IFLA_IFNAME, dev_name)
    self._SendNlRequest(RTM_GETLINK, ifinfo)
    hdr, data = cstruct.Read(self._Recv(), netlink.NLMsgHdr)
    if hdr.type == RTM_NEWLINK:
      return cstruct.Read(data, IfinfoMsg)
    elif hdr.type == netlink.NLMSG_ERROR:
      error = netlink.NLMsgErr(data).error
      raise IOError(error, os.strerror(-error))
    else:
      raise ValueError("Unknown Netlink Message Type %d" % hdr.type)
Пример #13
0
 def DumpSaInfo(self):
   """Returns a list of (SadbMsg, [(extension, attr), ...], ...) tuples."""
   dump = []
   msg = self.MakeSadbMsg(SADB_DUMP, SADB_TYPE_UNSPEC)
   received = self.SendAndRecv(msg, "")
   while received:
     msg, data = cstruct.Read(received, SadbMsg)
     extlen = self.ExtensionsLength(msg, SadbMsg)
     extensions, data = data[:extlen], data[extlen:]
     dump.append((msg, self.ParseExtensions(extensions)))
     if msg.seq == 0:  # End of dump.
       break
     received = self.Recv()
   return dump
Пример #14
0
    def _Decode(self, command, msg, nla_type, nla_data):
        """Decodes netlink attributes to Python types."""
        if msg.family == AF_INET or msg.family == AF_INET6:
            if isinstance(msg, InetDiagReqV2):
                prefix = "INET_DIAG_REQ"
            else:
                prefix = "INET_DIAG"
            name = self._GetConstantName(__name__, nla_type, prefix)
        else:
            # Don't know what this is. Leave it as an integer.
            name = nla_type

        if name in [
                "INET_DIAG_SHUTDOWN", "INET_DIAG_TOS", "INET_DIAG_TCLASS",
                "INET_DIAG_SKV6ONLY"
        ]:
            data = ord(nla_data)
        elif name == "INET_DIAG_CONG":
            data = nla_data.strip("\x00")
        elif name == "INET_DIAG_MEMINFO":
            data = InetDiagMeminfo(nla_data)
        elif name == "INET_DIAG_INFO":
            # TODO: Catch the exception and try something else if it's not TCP.
            data = TcpInfo(nla_data)
        elif name == "INET_DIAG_SKMEMINFO":
            data = SkMeminfo(nla_data)
        elif name == "INET_DIAG_MARK":
            data = struct.unpack("=I", nla_data)[0]
        elif name == "INET_DIAG_REQ_BYTECODE":
            data = self.DecodeBytecode(nla_data)
        elif name in ["INET_DIAG_LOCALS", "INET_DIAG_PEERS"]:
            data = []
            while len(nla_data):
                # The SCTP diag code always appears to copy sizeof(sockaddr_storage)
                # bytes, but does so from a union sctp_addr which is at most as long
                # as a sockaddr_in6.
                addr, nla_data = cstruct.Read(nla_data,
                                              csocket.SockaddrStorage)
                if addr.family == AF_INET:
                    addr = csocket.SockaddrIn(addr.Pack())
                elif addr.family == AF_INET6:
                    addr = csocket.SockaddrIn6(addr.Pack())
                data.append(addr)
        else:
            data = nla_data

        return name, data
Пример #15
0
def DecryptPacketWithNull(packet):
  """Apply null decryption to a packet.

  This performs ESP decapsulation on the given packet. The input packet is
  assumed to be a UDP packet. This function will remove the ESP header and
  trailer bytes from an ESP packet.

  TODO: Support TCP

  Args:
    packet: a scapy.IPv6 or scapy.IP packet

  Returns:
    A tuple of decrypted packet (scapy.IPv6 or scapy.IP) and EspHdr
  """
  esp_hdr, esp_data = cstruct.Read(str(packet.payload), xfrm.EspHdr)
  # Parse and strip ESP trailer.
  pad_len, esp_nexthdr = struct.unpack("BB", esp_data[-2:])
  trailer_len = pad_len + 2 # Add the size of the pad_len and next_hdr fields.
  LayerType = {
          IPPROTO_IPIP: scapy.IP,
          IPPROTO_IPV6: scapy.IPv6,
          IPPROTO_UDP: scapy.UDP}[esp_nexthdr]
  next_layer = LayerType(esp_data[:-trailer_len])
  if esp_nexthdr in [IPPROTO_IPIP, IPPROTO_IPV6]:
    # Tunnel mode decap is simple. Return the inner packet.
    return next_layer, esp_hdr

  # Cut out the ESP header.
  packet.payload = next_layer
  # Fix the IPv4/IPv6 headers.
  if type(packet) is scapy.IPv6:
    packet.nh = IPPROTO_UDP
    packet.plen = None # Recompute packet length.
    packet = scapy.IPv6(str(packet))
  elif type(packet) is scapy.IP:
    packet.proto = IPPROTO_UDP
    packet.len = None # Recompute packet length.
    packet.chksum = None # Recompute IPv4 checksum.
    packet = scapy.IP(str(packet))
  else:
    raise ValueError("First layer in packet should be IPv4 or IPv6: " + repr(packet))
  return packet, esp_hdr
    def _ParseAttributes(self, command, family, msg, data):
        """Parses and decodes netlink attributes.

    Takes a block of NLAttr data structures, decodes them using Decode, and
    returns the result in a dict keyed by attribute number.

    Args:
      command: An integer, the rtnetlink command being carried out.
      family: The address family.
      msg: A Struct, the type of the data after the netlink header.
      data: A byte string containing a sequence of NLAttr data structures.

    Returns:
      A dictionary mapping attribute types (integers) to decoded values.

    Raises:
      ValueError: There was a duplicate attribute type.
    """
        attributes = {}
        while data:
            # Read the nlattr header.
            nla, data = cstruct.Read(data, NLAttr)

            # Read the data.
            datalen = nla.nla_len - len(nla)
            padded_len = PaddedLength(nla.nla_len) - len(nla)
            nla_data, data = data[:datalen], data[padded_len:]

            # If it's an attribute we know about, try to decode it.
            nla_name, nla_data = self._Decode(command, msg, nla.nla_type,
                                              nla_data)

            # We only support unique attributes for now, except for INET_DIAG_NONE,
            # which can appear more than once but doesn't seem to contain any data.
            if nla_name in attributes and nla_name != "INET_DIAG_NONE":
                raise ValueError("Duplicate attribute %s" % nla_name)

            attributes[nla_name] = nla_data
            self._Debug("      %s" % str((nla_name, nla_data)))

        return attributes