#!/usr/bin/env python
"""
Netlink socket experiments.
Olivier Mehani <olivier.mehani@inria.fr>, 2009
$Id$
"""
import sys
import os
import string
from errno import errorcode
from socket import *
import select
import struct
from collections import namedtuple
# from linux/netlink.h
NETLINK_ROUTE=0 # Routing/device hook
NETLINK_UNUSED=1 # Unused number
NETLINK_USERSOCK=2 # Reserved for user mode socket protocols
NETLINK_FIREWALL=3 # Firewalling hook
NETLINK_INET_DIAG=4 # INET socket monitoring
NETLINK_NFLOG=5 # netfilter/iptables ULOG
NETLINK_XFRM=6 # ipsec
NETLINK_SELINUX=7 # SELinux event notifications
NETLINK_ISCSI=8 # Open-iSCSI
NETLINK_AUDIT=9 # auditing
NETLINK_FIB_LOOKUP=10
NETLINK_CONNECTOR=11
NETLINK_NETFILTER=12 # netfilter subsystem
NETLINK_IP6_FW=13
NETLINK_DNRTMSG=14 # DECnet routing messages
NETLINK_KOBJECT_UEVENT=15 # Kernel messages to userspace
NETLINK_GENERIC=16
NETLINK_SCSITRANSPORT=18 # SCSI Transports
NETLINK_ECRYPTFS=19
nl_groups = {
NETLINK_ROUTE: "NETLINK_ROUTE",
NETLINK_UNUSED: "NETLINK_UNUSED",
NETLINK_USERSOCK: "NETLINK_USERSOCK",
NETLINK_FIREWALL: "NETLINK_FIREWALL",
NETLINK_INET_DIAG: "NETLINK_INET_DIAG",
NETLINK_NFLOG: "NETLINK_NFLOG",
NETLINK_XFRM: "NETLINK_XFRM",
NETLINK_SELINUX: "NETLINK_SELINUX",
NETLINK_ISCSI: "NETLINK_ISCSI",
NETLINK_AUDIT: "NETLINK_AUDIT",
NETLINK_FIB_LOOKUP: "NETLINK_FIB_LOOKUP",
NETLINK_CONNECTOR: "NETLINK_CONNECTOR",
NETLINK_NETFILTER: "NETLINK_NETFILTER",
NETLINK_IP6_FW: "NETLINK_IP6_FW",
NETLINK_DNRTMSG: "NETLINK_DNRTMSG",
NETLINK_KOBJECT_UEVENT: "NETLINK_KOBJECT_UEVENT",
NETLINK_GENERIC: "NETLINK_GENERIC",
NETLINK_SCSITRANSPORT: "NETLINK_SCSITRANSPORT",
NETLINK_ECRYPTFS: "NETLINK_ECRYPTFS",
}
# from linux/rtnetlink.h
RTM_BASE=16
RTM_NEWLINK=16
RTM_DELLINK=17
RTM_GETLINK=18
RTM_SETLINK=19
RTM_NEWADDR=20
RTM_DELADDR=21
RTM_GETADDR=22
RTM_NEWROUTE=24
RTM_DELROUTE=25
RTM_GETROUTE=26
RTM_NEWNEIGH=28
RTM_DELNEIGH=29
RTM_GETNEIGH=30
RTM_NEWRULE=32
RTM_DELRULE=33
RTM_GETRULE=34
RTM_NEWQDISC=36
RTM_DELQDISC=37
RTM_GETQDISC=38
RTM_NEWTCLASS=40
RTM_DELTCLASS=41
RTM_GETTCLASS=42
RTM_NEWTFILTER=44
RTM_DELTFILTER=45
RTM_GETTFILTER=46
RTM_NEWACTION=48
RTM_DELACTION=49
RTM_GETACTION=50
RTM_NEWPREFIX=52
RTM_GETMULTICAST=58
RTM_GETANYCAST=62
RTM_NEWNEIGHTBL=64
RTM_GETNEIGHTBL=66
RTM_SETNEIGHTBL=65
RTM_NEWNDUSEROPT=68
RTM_NEWADDRLABEL=72
RTM_DELADDRLABEL=73
RTM_GETADDRLABEL=74
RTM_GETDCB=78
RTM_SETDCB=79
rtnl_msg_types = {
RTM_NEWLINK: "RTM_NEWLINK",
RTM_DELLINK: "RTM_DELLINK",
RTM_GETLINK: "RTM_GETLINK",
RTM_SETLINK: "RTM_SETLINK",
RTM_NEWADDR: "RTM_NEWADDR",
RTM_DELADDR: "RTM_DELADDR",
RTM_GETADDR: "RTM_GETADDR",
RTM_NEWROUTE: "RTM_NEWROUTE",
RTM_DELROUTE: "RTM_DELROUTE",
RTM_GETROUTE: "RTM_GETROUTE",
RTM_NEWNEIGH: "RTM_NEWNEIGH",
RTM_DELNEIGH: "RTM_DELNEIGH",
RTM_GETNEIGH: "RTM_GETNEIGH",
RTM_NEWRULE: "RTM_NEWRULE",
RTM_DELRULE: "RTM_DELRULE",
RTM_GETRULE: "RTM_GETRULE",
RTM_NEWQDISC: "RTM_NEWQDISC",
RTM_DELQDISC: "RTM_DELQDISC",
RTM_GETQDISC: "RTM_GETQDISC",
RTM_NEWTCLASS: "RTM_NEWTCLASS",
RTM_DELTCLASS: "RTM_DELTCLASS",
RTM_GETTCLASS: "RTM_GETTCLASS",
RTM_NEWTFILTER: "RTM_NEWTFILTER",
RTM_DELTFILTER: "RTM_DELTFILTER",
RTM_GETTFILTER: "RTM_GETTFILTER",
RTM_NEWACTION: "RTM_NEWACTION",
RTM_DELACTION: "RTM_DELACTION",
RTM_GETACTION: "RTM_GETACTION",
RTM_NEWPREFIX: "RTM_NEWPREFIX",
RTM_GETMULTICAST: "RTM_GETMULTICAST",
RTM_GETANYCAST: "RTM_GETANYCAST",
RTM_NEWNEIGHTBL: "RTM_NEWNEIGHTBL",
RTM_GETNEIGHTBL: "RTM_GETNEIGHTBL",
RTM_SETNEIGHTBL: "RTM_SETNEIGHTBL",
RTM_NEWNDUSEROPT: "RTM_NEWNDUSEROPT",
RTM_NEWADDRLABEL: "RTM_NEWADDRLABEL",
RTM_DELADDRLABEL: "RTM_DELADDRLABEL",
RTM_GETADDRLABEL: "RTM_GETADDRLABEL",
RTM_GETDCB: "RTM_GETDCB",
RTM_SETDCB: "RTM_SETDCB",
}
RTMGRP_LINK=1
RTMGRP_NOTIFY=2
RTMGRP_NEIGH=4
RTMGRP_TC=8
RTMGRP_IPV4_IFADDR=0x10
RTMGRP_IPV4_MROUTE=0x20
RTMGRP_IPV4_ROUTE=0x40
RTMGRP_IPV4_RULE=0x80
RTMGRP_IPV6_IFADDR=0x100
RTMGRP_IPV6_MROUTE=0x200
RTMGRP_IPV6_ROUTE=0x400
RTMGRP_IPV6_IFINFO=0x800
RTMGRP_DECnet_IFADDR=0x1000
RTMGRP_DECnet_ROUTE=0x4000
RTMGRP_IPV6_PREFIX=0x20000
rtnl_groups = {
RTMGRP_LINK: "RTMGRP_LINK",
RTMGRP_NOTIFY: "RTMGRP_NOTIFY",
RTMGRP_NEIGH: "RTMGRP_NEIGH",
RTMGRP_TC: "RTMGRP_TC",
RTMGRP_IPV4_IFADDR: "RTMGRP_IPV4_IFADDR",
RTMGRP_IPV4_MROUTE: "RTMGRP_IPV4_MROUTE",
RTMGRP_IPV4_ROUTE: "RTMGRP_IPV4_ROUTE",
RTMGRP_IPV4_RULE: "RTMGRP_IPV4_RULE",
RTMGRP_IPV6_IFADDR: "RTMGRP_IPV6_IFADDR",
RTMGRP_IPV6_MROUTE: "RTMGRP_IPV6_MROUTE",
RTMGRP_IPV6_ROUTE: "RTMGRP_IPV6_ROUTE",
RTMGRP_IPV6_IFINFO: "RTMGRP_IPV6_IFINFO",
RTMGRP_DECnet_IFADDR: "RTMGRP_DECnet_IFADDR",
RTMGRP_DECnet_ROUTE: "RTMGRP_DECnet_ROUTE",
RTMGRP_IPV6_PREFIX: "RTMGRP_IPV6_PREFIX",
}
# from linux/if_addr.h
IFA_F_SECONDARY = 0x01
IFA_F_TEMPORARY = IFA_F_SECONDARY
IFA_F_NODAD = 0x02
IFA_F_OPTIMISTIC = 0x04
IFA_F_HOMEADDRESS = 0x10
IFA_F_DEPRECATED = 0x20
IFA_F_TENTATIVE = 0x40
IFA_F_PERMANENT = 0x80
ifa_flags = {
0x01: "IFA_F_SECONDARY",
# IFA_F_SECONDARY: "IFA_F_TEMPORARY",
0x02: "IFA_F_NODAD",
0x04: "IFA_F_OPTIMISTIC",
0x10: "IFA_F_HOMEADDRESS",
0x20: "IFA_F_DEPRECATED",
0x40: "IFA_F_TENTATIVE",
0x80: "IFA_F_PERMANENT",
}
IFA_UNSPEC = 0
IFA_ADDRESS = 1
IFA_LOCAL = 2
IFA_LABEL = 3
IFA_BROADCAST = 4
IFA_ANYCAST = 5
IFA_CACHEINFO = 6
IFA_MULTICAST = 7
ifa_types = {
0: "IFA_UNSPEC",
1: "IFA_ADDRESS",
2: "IFA_LOCAL",
3: "IFA_LABEL",
4: "IFA_BROADCAST",
5: "IFA_ANYCAST",
6: "IFA_CACHEINFO",
7: "IFA_MULTICAST",
}
# in linux/if.h
IFF_UP = 0x1 # interface is up
IFF_BROADCAST = 0x2 # broadcast address valid
IFF_DEBUG = 0x4 # turn on debugging
IFF_LOOPBACK = 0x8 # is a loopback net
IFF_POINTOPOINT = 0x10 # interface is has p-p link
IFF_NOTRAILERS = 0x20 # avoid use of trailers
IFF_RUNNING = 0x40 # interface RFC2863 OPER_UP
IFF_NOARP = 0x80 # no ARP protocol
IFF_PROMISC = 0x100 # receive all packets
IFF_ALLMULTI = 0x200 # receive all multicast packets
IFF_MASTER = 0x400 # master of a load balancer
IFF_SLAVE = 0x800 # slave of a load balancer
IFF_MULTICAST = 0x1000 # Supports multicast
IFF_PORTSEL = 0x2000 # can set media type
IFF_AUTOMEDIA = 0x4000 # auto media select active
IFF_DYNAMIC = 0x8000 # dialup device with changing addresses
IFF_LOWER_UP = 0x10000 # driver signals L1 up
IFF_DORMANT = 0x20000 # driver signals dormant
IFF_ECHO = 0x40000 # echo sent packets
iff_flags = {
IFF_UP: "IFF_UP",
IFF_BROADCAST: "IFF_BROADCAST",
IFF_DEBUG: "IFF_DEBUG",
IFF_LOOPBACK: "IFF_LOOPBACK",
IFF_POINTOPOINT:"IFF_POINTOPOINT",
IFF_NOTRAILERS: "IFF_NOTRAILERS",
IFF_RUNNING: "IFF_RUNNING",
IFF_NOARP: "IFF_NOARP",
IFF_PROMISC: "IFF_PROMISC",
IFF_ALLMULTI: "IFF_ALLMULTI",
IFF_MASTER: "IFF_MASTER",
IFF_SLAVE: "IFF_SLAVE",
IFF_MULTICAST: "IFF_MULTICAST",
IFF_PORTSEL: "IFF_PORTSEL",
IFF_AUTOMEDIA: "IFF_AUTOMEDIA",
IFF_DYNAMIC: "IFF_DYNAMIC",
IFF_LOWER_UP: "IFF_LOWER_UP",
IFF_DORMANT: "IFF_DORMANT",
IFF_ECHO: "IFF_ECHO",
}
# in linux/if_link.h
IFLA_UNSPEC = 0
IFLA_ADDRESS = 1
IFLA_BROADCAST = 2
IFLA_IFNAME = 3
IFLA_MTU = 4
IFLA_LINK = 5
IFLA_QDISC = 6
IFLA_STATS = 7
IFLA_COST = 8
IFLA_PRIORITY = 9
IFLA_MASTER = 10
IFLA_WIRELESS = 11 # Wireless Extension event - see wireless.h
IFLA_PROTINFO = 12 # Protocol specific information for a link
IFLA_TXQLEN = 13
IFLA_MAP = 14
IFLA_WEIGHT = 15
IFLA_OPERSTATE = 16
IFLA_LINKMODE = 17
IFLA_LINKINFO = 18
IFLA_NET_NS_PID = 19
IFLA_IFALIAS = 20
ifla_types = {
IFLA_UNSPEC: "IFLA_UNSPEC",
IFLA_ADDRESS: "IFLA_ADDRESS",
IFLA_BROADCAST: "IFLA_BROADCAST",
IFLA_IFNAME: "IFLA_IFNAME",
IFLA_MTU: "IFLA_MTU",
IFLA_LINK: "IFLA_LINK",
IFLA_QDISC: "IFLA_QDISC",
IFLA_STATS: "IFLA_STATS",
IFLA_COST: "IFLA_COST",
IFLA_PRIORITY: "IFLA_PRIORITY",
IFLA_MASTER: "IFLA_MASTER",
IFLA_WIRELESS: "IFLA_WIRELESS",
IFLA_PROTINFO: "IFLA_PROTINFO",
IFLA_TXQLEN: "IFLA_TXQLEN",
IFLA_MAP: "IFLA_MAP",
IFLA_WEIGHT: "IFLA_WEIGHT",
IFLA_OPERSTATE: "IFLA_OPERSTATE",
IFLA_LINKMODE: "IFLA_LINKMODE",
IFLA_LINKINFO: "IFLA_LINKINFO",
IFLA_NET_NS_PID: "IFLA_NET_NS_PID",
IFLA_IFALIAS: "IFLA_IFALIAS",
}
# in linux/neighbour.h
NTF_USE = 0x01
NTF_PROXY = 0x08 #ATF_PUBL
NTF_ROUTER = 0x80
nd_flags = {
NTF_USE: "NTF_USE",
NTF_PROXY: "NTF_PROXY",
NTF_ROUTER: "NTF_ROUTER",
}
NUD_INCOMPLETE = 0x01
NUD_REACHABLE = 0x02
NUD_STALE = 0x04
NUD_DELAY = 0x08
NUD_PROBE = 0x10
NUD_FAILED = 0x20
NUD_NOARP = 0x40
NUD_PERMANENT = 0x80
NUD_NONE = 0x00
nd_states = {
NUD_INCOMPLETE: "NUD_INCOMPLETE",
NUD_REACHABLE: "NUD_REACHABLE",
NUD_STALE: "NUD_STALE",
NUD_DELAY: "NUD_DELAY",
NUD_PROBE: "NUD_PROBE",
NUD_FAILED: "NUD_FAILED",
NUD_NOARP: "NUD_NOARP",
NUD_PERMANENT: "NUD_PERMANENT",
NUD_NONE: "NUD_NONE",
}
NDA_UNSPEC = 0
NDA_DST = 1
NDA_LLADDR = 2
NDA_CACHEINFO = 3
NDA_PROBES = 4
nda_types = {
NDA_UNSPEC: "NDA_UNSPEC",
NDA_DST: "NDA_DST",
NDA_LLADDR: "NDA_LLADDR",
NDA_CACHEINFO: "NDA_CACHEINFO",
NDA_PROBES: "NDA_PROBES",
}
NDTA_UNSPEC = 0
NDTA_NAME = 1 # char *, unchangeable
NDTA_THRESH1 = 2 # u32
NDTA_THRESH2 = 3 # u32
NDTA_THRESH3 = 4 # u32
NDTA_CONFIG = 5 # struct ndt_config, read-only
NDTA_PARMS = 6 # nested TLV NDTPA_*
NDTA_STATS = 7 # struct ndt_stats, read-only
NDTA_GC_INTERVAL = 8 # u64, msecs
ndta_types = {
NDTA_UNSPEC: "NDTA_UNSPEC",
NDTA_NAME: "NDTA_NAME",
NDTA_THRESH1: "NDTA_THRESH1",
NDTA_THRESH2: "NDTA_THRESH2",
NDTA_THRESH3: "NDTA_THRESH3",
NDTA_CONFIG: "NDTA_CONFIG",
NDTA_PARMS: "NDTA_PARMS",
NDTA_STATS: "NDTA_STATS",
NDTA_GC_INTERVAL: "NDTA_GC_INTERVAL",
}
# in linux/rtnetlink.h
RTN_UNSPEC = 0
RTN_UNICAST = 1 # Gateway or direct route
RTN_LOCAL = 2 # Accept locally
RTN_BROADCAST = 3 # Accept locally as broadcast = send as broadcast
RTN_ANYCAST = 4 # Accept locally as broadcast = but send as unicast
RTN_MULTICAST = 5 # Multicast route
RTN_BLACKHOLE = 6 # Drop
RTN_UNREACHABLE = 7 # Destination is unreachable
RTN_PROHIBIT = 8 # Administratively prohibited
RTN_THROW = 9 # Not in this table
RTN_NAT = 10 # Translate this address
RTN_XRESOLVE = 11 # Use external resolver
rtm_type = {
RTN_UNSPEC: "RTN_UNSPEC",
RTN_UNICAST: "RTN_UNICAST",
RTN_LOCAL: "RTN_LOCAL",
RTN_BROADCAST: "RTN_BROADCAST",
RTN_ANYCAST: "RTN_ANYCAST",
RTN_MULTICAST: "RTN_MULTICAST",
RTN_BLACKHOLE: "RTN_BLACKHOLE",
RTN_UNREACHABLE: "RTN_UNREACHABLE",
RTN_PROHIBIT: "RTN_PROHIBIT",
RTN_THROW: "RTN_THROW",
RTN_NAT: "RTN_NAT",
RTN_XRESOLVE: "RTN_XRESOLVE",
}
RTPROT_UNSPEC = 0
RTPROT_REDIRECT = 1
RTPROT_KERNEL = 2
RTPROT_BOOT = 3
RTPROT_STATIC = 4
RTPROT_GATED = 5
RTPROT_RA = 6
RTPROT_MRT = 7
RTPROT_ZEBRA = 8
RTPROT_BIRD = 9
RTPROT_DNROUTED = 10
RTPROT_XORP = 11
RTPROT_NTK = 12
RTPROT_DHCP = 13
rtm_protocol = {
RTPROT_UNSPEC: "RTPROT_UNSPEC",
RTPROT_REDIRECT: "RTPROT_REDIRECT",
RTPROT_KERNEL: "RTPROT_KERNEL",
RTPROT_BOOT: "RTPROT_BOOT",
RTPROT_STATIC: "RTPROT_STATIC",
RTPROT_GATED: "RTPROT_GATED",
RTPROT_RA: "RTPROT_RA",
RTPROT_MRT: "RTPROT_MRT",
RTPROT_ZEBRA: "RTPROT_ZEBRA",
RTPROT_BIRD: "RTPROT_BIRD",
RTPROT_DNROUTED: "RTPROT_DNROUTED",
RTPROT_XORP: "RTPROT_XORP",
RTPROT_NTK: "RTPROT_NTK",
RTPROT_DHCP: "RTPROT_DHCP",
}
RT_SCOPE_UNIVERSE = 0
RT_SCOPE_SITE = 200
RT_SCOPE_LINK = 253
RT_SCOPE_HOST = 254
RT_SCOPE_NOWHERE = 255
rtm_scope = {
RT_SCOPE_UNIVERSE: "RT_SCOPE_UNIVERSE",
RT_SCOPE_SITE: "RT_SCOPE_SITE",
RT_SCOPE_LINK: "RT_SCOPE_LINK",
RT_SCOPE_HOST: "RT_SCOPE_HOST",
RT_SCOPE_NOWHERE: "RT_SCOPE_NOWHERE",
}
RTM_F_NOTIFY = 0x100 # Notify user of route change
RTM_F_CLONED = 0x200 # This route is cloned
RTM_F_EQUALIZE = 0x400 # Multipath equalizer: NI
RTM_F_PREFIX = 0x800 # Prefix addresses
rtm_flags = {
RTM_F_NOTIFY: "RTM_F_NOTIFY",
RTM_F_CLONED: "RTM_F_CLONED",
RTM_F_EQUALIZE: "RTM_F_EQUALIZE",
RTM_F_PREFIX: "RTM_F_PREFIX",
}
RTA_UNSPEC = 0
RTA_DST = 1
RTA_SRC = 2
RTA_IIF = 3
RTA_OIF = 4
RTA_GATEWAY = 5
RTA_PRIORITY = 6
RTA_PREFSRC = 7
RTA_METRICS = 8
RTA_MULTIPATH = 9
RTA_PROTOINFO = 10 # no longer used
RTA_FLOW = 11
RTA_CACHEINFO = 12
RTA_SESSION = 13 # no longer used
RTA_MP_ALGO = 14 # no longer used
RTA_TABLE = 15
rta_types = {
RTA_UNSPEC: "RTA_UNSPEC",
RTA_DST: "RTA_DST",
RTA_SRC: "RTA_SRC",
RTA_IIF: "RTA_IIF",
RTA_OIF: "RTA_OIF",
RTA_GATEWAY: "RTA_GATEWAY",
RTA_PRIORITY: "RTA_PRIORITY",
RTA_PREFSRC: "RTA_PREFSRC",
RTA_METRICS: "RTA_METRICS",
RTA_MULTIPATH: "RTA_MULTIPATH",
RTA_PROTOINFO: "RTA_PROTOINFO",
RTA_FLOW: "RTA_FLOW",
RTA_CACHEINFO: "RTA_CACHEINFO",
RTA_SESSION: "RTA_SESSION",
RTA_MP_ALGO: "RTA_MP_ALGO",
RTA_TABLE: "RTA_TABLE",
}
RTAX_UNSPEC = 0
RTAX_LOCK = 1
RTAX_MTU = 2
RTAX_WINDOW = 3
RTAX_RTT = 4
RTAX_RTTVAR = 5
RTAX_SSTHRESH = 6
RTAX_CWND = 7
RTAX_ADVMSS = 8
RTAX_REORDERING = 9
RTAX_HOPLIMIT = 10
RTAX_INITCWND = 11
RTAX_FEATURES = 12
RTAX_RTO_MIN = 13
rtax_metrics = {
RTAX_UNSPEC: "RTAX_UNSPEC",
RTAX_LOCK: "RTAX_LOCK",
RTAX_MTU: "RTAX_MTU",
RTAX_WINDOW: "RTAX_WINDOW",
RTAX_RTT: "RTAX_RTT",
RTAX_RTTVAR: "RTAX_RTTVAR",
RTAX_SSTHRESH: "RTAX_SSTHRESH",
RTAX_CWND: "RTAX_CWND",
RTAX_ADVMSS: "RTAX_ADVMSS",
RTAX_REORDERING: "RTAX_REORDERING",
RTAX_HOPLIMIT: "RTAX_HOPLIMIT",
RTAX_INITCWND: "RTAX_INITCWND",
RTAX_FEATURES: "RTAX_FEATURES",
RTAX_RTO_MIN: "RTAX_RTO_MIN",
}
# in linux/inet_diag.h
TCPDIAG_GETSOCK = 18
DCCPDIAG_GETSOCK = 19
diag_types = {
TCPDIAG_GETSOCK: "TCPDIAG_GETSOCK",
DCCPDIAG_GETSOCK: "DCCPDIAG_GETSOCK",
}
INET_DIAG_NONE = 0
INET_DIAG_MEMINFO = 1
INET_DIAG_INFO = 2
INET_DIAG_VEGASINFO = 3
INET_DIAG_CONG = 4
diag_extensions = {
INET_DIAG_NONE: "INET_DIAG_NONE",
INET_DIAG_MEMINFO: "INET_DIAG_MEMINFO",
INET_DIAG_INFO: "INET_DIAG_INFO",
INET_DIAG_VEGASINFO:"INET_DIAG_VEGASINFO",
INET_DIAG_CONG: "INET_DIAG_CONG",
}
INET_DIAG_ALL_F = (1<<INET_DIAG_CONG)-1
# in misc/ss.c from iproute2
DB_TCP = 1<<0
DB_DCCP = 1<<1
DB_UDP = 1<<2
DB_RAW = 1<<3
DB_UNIX_DG = 1<<4
DB_UNIX_ST = 1<<5
DB_PACKET_DG = 1<<6
DB_PACKET_R = 1<<7
DB_NETLINK = 1<<8
diag_dbs = {
DB_TCP: "DB_TCP",
DB_DCCP: "DB_DCCP",
DB_UDP: "DB_UDP",
DB_RAW: "DB_RAW",
DB_UNIX_DG: "DB_UNIX_DG",
DB_UNIX_ST: "DB_UNIX_ST",
DB_PACKET_DG: "DB_PACKET_DG",
DB_PACKET_R: "DB_PACKET_R",
DB_NETLINK: "DB_NETLINK",
}
SS_UNKNOWN = 0
SS_ESTABLISHED = 1
SS_SYN_SENT = 2
SS_SYN_RECV = 3
SS_FIN_WAIT1 = 4
SS_FIN_WAIT2 = 5
SS_TIME_WAIT = 6
SS_CLOSE = 7
SS_CLOSE_WAIT = 8
SS_LAST_ACK = 9
SS_LISTEN = 10
SS_CLOSING = 11
sock_states = {
SS_UNKNOWN: "SS_UNKNOWN",
SS_ESTABLISHED: "SS_ESTABLISHED",
SS_SYN_SENT: "SS_SYN_SENT",
SS_SYN_RECV: "SS_SYN_RECV",
SS_FIN_WAIT1: "SS_FIN_WAIT1",
SS_FIN_WAIT2: "SS_FIN_WAIT2",
SS_TIME_WAIT: "SS_TIME_WAIT",
SS_CLOSE: "SS_CLOSE",
SS_CLOSE_WAIT: "SS_CLOSE_WAIT",
SS_LAST_ACK: "SS_LAST_ACK",
SS_LISTEN: "SS_LISTEN",
SS_CLOSING: "SS_CLOSING",
}
SS_ALL_F = (1<<SS_CLOSING+1) - 1
NLM_F_REQUEST = 1 # It is request message.
NLM_F_MULTI = 2 # Multipart message, terminated by NLMSG_DONE
NLM_F_ACK = 4 # Reply with ack, with zero or error code
NLM_F_ECHO = 8 # Echo this request
# Modifiers to GET request
NLM_F_ROOT = 0x100 # specify tree root
NLM_F_MATCH = 0x200 # return all matching
NLM_F_ATOMIC = 0x400 # atomic GET
NLM_F_DUMP = (NLM_F_ROOT|NLM_F_MATCH)
#Modifiers to NEW request
NLM_F_REPLACE = 0x100 # Override existing
NLM_F_EXCL = 0x200 # Do not touch, if it exists
NLM_F_CREATE = 0x400 # Create, if it does not exist
NLM_F_APPEND = 0x800 # Add to end of list
nlm_flags = {
NLM_F_REQUEST: "NLM_F_REQUEST",
NLM_F_MULTI: "NLM_F_MULTI",
NLM_F_ACK: "NLM_F_ACK",
NLM_F_ECHO: "NLM_F_ECHO",
NLM_F_ROOT: "NLM_F_ROOT",
NLM_F_MATCH: "NLM_F_MATCH",
NLM_F_ATOMIC: "NLM_F_ATOMIC",
NLM_F_DUMP: "NLM_F_DUMP",
NLM_F_REPLACE: "NLM_F_REPLACE",
NLM_F_EXCL: "NLM_F_EXCL",
NLM_F_CREATE: "NLM_F_CREATE",
NLM_F_APPEND: "NLM_F_APPEND",
}
NLMSG_NOOP = 0x1 # Nothing.
NLMSG_ERROR = 0x2 # Error
NLMSG_DONE = 0x3 # End of a dump
NLMSG_OVERRUN = 0x4 # Data lost
NLMSG_MIN_TYPE = 0x10 # < 0x10: reserved control messages
nlmsg_types = {
NLMSG_NOOP: "NLMSG_NOOP",
NLMSG_ERROR: "NLMSG_ERROR",
NLMSG_DONE: "NLMSG_DONE",
NLMSG_OVERRUN: "NLMSG_OVERRUN",
NLMSG_MIN_TYPE: "NLMSG_MIN_TYPE",
}
# in linux/tcp.h
TCP_NODELAY = 1 # Turn off Nagle's algorithm.
TCP_MAXSEG = 2 # Limit MSS
TCP_CORK = 3 # Never send partially complete segments
TCP_KEEPIDLE = 4 # Start keeplives after this period
TCP_KEEPINTVL = 5 # Interval between keepalives
TCP_KEEPCNT = 6 # Number of keepalives before death
TCP_SYNCNT = 7 # Number of SYN retransmits
TCP_LINGER2 = 8 # Life time of orphaned FIN-WAIT-2 state
TCP_DEFER_ACCEPT= 9 # Wake up listener only when data arrive
TCP_WINDOW_CLAMP= 10 # Bound advertised window
TCP_INFO = 11 # Information about this connection.
TCP_QUICKACK = 12 # Block/reenable quick acks
TCP_CONGESTION = 13 # Congestion control algorithm
TCP_MD5SIG = 14 # TCP MD5 Signature (RFC2385)
tcp_options = {
TCP_NODELAY: "TCP_NODELAY",
TCP_MAXSEG: "TCP_MAXSEG",
TCP_CORK: "TCP_CORK",
TCP_KEEPIDLE: "TCP_KEEPIDLE",
TCP_KEEPINTVL: "TCP_KEEPINTVL",
TCP_KEEPCNT: "TCP_KEEPCNT",
TCP_SYNCNT: "TCP_SYNCNT",
TCP_LINGER2: "TCP_LINGER2",
TCP_DEFER_ACCEPT: "TCP_DEFER_ACCEPT",
TCP_WINDOW_CLAMP: "TCP_WINDOW_CLAMP",
TCP_INFO: "TCP_INFO",
TCP_QUICKACK: "TCP_QUICKACK",
TCP_CONGESTION: "TCP_CONGESTION",
TCP_MD5SIG: "TCP_MD5SIG",
}
TCPI_OPT_TIMESTAMPS = 1
TCPI_OPT_SACK = 2
TCPI_OPT_WSCALE = 4
TCPI_OPT_ECN = 8
tcpi_options = {
TCPI_OPT_TIMESTAMPS:"TCPI_OPT_TIMESTAMPS",
TCPI_OPT_SACK: "TCPI_OPT_SACK",
TCPI_OPT_WSCALE: "TCPI_OPT_WSCALE",
TCPI_OPT_ECN: "TCPI_OPT_ECN",
}
TCP_CA_Open = 0
TCP_CA_Disorder = 1
TCP_CA_CWR = 2
TCP_CA_Recovery = 3
TCP_CA_Loss = 4
tcp_ca_states = {
TCP_CA_Open: "TCP_CA_Open",
TCP_CA_Disorder: "TCP_CA_Disorder",
TCP_CA_CWR: "TCP_CA_CWR",
TCP_CA_Recovery: "TCP_CA_Recovery",
TCP_CA_Loss: "TCP_CA_Loss",
}
## For reference: transform CPP #define into Python variable with Vim
## '<,'>s/#define \([A-Z_0-9]\+\)\s\+\(\(0x\)\?[0-9]\+\)\s*\(\/\*\(.*\)\s*\*\/\)\?/\1\t= \2\t# \5/
## and generate the enum...
## '<,'>s/\([A-Z_0-9]\+\)\s\+.*/ \1:\t"\1",
# Helper functions
def print_hex(str, offset=0, prev_offset=0):
i = offset + prev_offset
if len(str) <= offset:
return
for c in str[offset:]:
if i == offset or not i%16:
curstr = ""
sys.stdout.write('%0.4X:\t' % i)
sys.stdout.write('%.2X' % ord(c))
curstr += c if c in string.printable and c not in "\t\r\n" else "."
i+=1
if not i%16:
sys.stdout.write("\t" + curstr + "\n")
elif not i%2:
sys.stdout.write(" ")
if i%16:
sys.stdout.write("\t" + curstr + "\n")
# functions reminiscent of RTA_* macros in linux/rtnetlink.h
RTA_SIZE = 4
RTA_ALIGNTO = RTA_SIZE
def rtattr(buf, offset):
return buf[offset:offset+4]
def rta_offset_ok(offset, buflen):
return offset + RTA_SIZE < buflen
def rta_align_length(attrlen):
adjlen = (attrlen + RTA_ALIGNTO-1) & ~(RTA_ALIGNTO-1)
if adjlen != attrlen:
sys.stdout.write(" attribute alignement %d\n" % (adjlen - attrlen))
return adjlen
def rta_data_offset(offset):
return offset + RTA_SIZE
# rtattr from linux/rtnetlink.h
def parse_rtattr(attr, attr_types=None, silent=False):
if len(attr) != RTA_SIZE:
raise IndexError("rtattr are %d bits long" % RTA_SIZE)
attrlen, attrtype = struct.unpack('HH', attr)
if not silent:
if attr_types:
sys.stdout.write(" attribute length %d, type %s\n" % (attrlen, attr_types[attrtype]))
else:
sys.stdout.write(" attribute length %d, type %d\n" % (attrlen, attrtype))
return (attrlen, attrtype)
def format_address(af, address):
if af == AF_INET:
return ".".join(map(lambda x: '%d' % x, address))
elif af == AF_INET6:
return ":".join(map(lambda x: '%x' % x, address))
else:
return "-".join(map(lambda x: '%.x' % x, address))
def parse_address(af, buf):
# XXX: only addresses seem to be in network order (?)
if af == AF_INET6:
return struct.unpack('>HHHHHHHH', buf[:16])
elif af is AF_INET:
return struct.unpack('>BBBB', buf[:4])
else:
sys.stderr.write("error: unhandled af %d\n", af)
return []
def parse_lladdr(buf):
address = []
for offset in xrange(len(buf)):
address.append(struct.unpack_from("B", buf[offset:offset+1]))
return address
def parse_link_message(buf, type):
# Message structure: ifinfomsg ()
# See RFC 3549
# from linux/rtnetlink.h
af, iftype, index, flags, change = struct.unpack('BxHIII', buf[:16])
sys.stdout.write(" Link message (%s): AF %d, iftype %d, index %d, flags %s, change %d\n"
% (rtnl_msg_types[type], af, iftype, index,
"|".join([iff_flags[c] for c in iff_flags.keys() if c&flags]),
change))
offset = 16
while rta_offset_ok(offset, len(buf)):
attrlen, attrtype = parse_rtattr(rtattr(buf,offset), ifla_types)
payload_offset = rta_data_offset(offset)
if attrtype is IFLA_IFNAME:
sys.stdout.write(" interface name %s\n" % buf[payload_offset:offset+attrlen])
elif attrtype is IFLA_ADDRESS:
address = parse_lladdr(buf[payload_offset:offset + attrlen])
sys.stdout.write(" link-layer address: %s\n"
% (format_address(af, address)))
elif attrtype is IFLA_MTU:
mtu = struct.unpack("I", buf[payload_offset:offset+attrlen])
sys.stdout.write(" MTU: %d\n" % mtu)
elif attrtype is IFLA_PROTINFO:
sys.stdout.write(" SKIPPED PARSING\n")
else:
print_hex(buf[:offset+attrlen], payload_offset)
offset += rta_align_length(attrlen)
return offset
def parse_addr_message(buf, type):
# Message structure: ifaddrmsg, (rtattr, address|cacheinfo)+
# from linux/if_addr.h
af, prefixlen, flags, scope, index = struct.unpack('BBBBI', buf[:8])
sys.stdout.write (" Address message (%s): AF %d, prefixlen %d, flags %s, scope %d, index %d\n"
% (rtnl_msg_types[type], af, prefixlen,"|".join([ifa_flags[c]
for c in ifa_flags.keys() if c&flags]), scope, index))
offset = 8
while rta_offset_ok(offset, len(buf)):
attrlen, attrtype = parse_rtattr(rtattr(buf,offset), ifa_types)
payload_offset = rta_data_offset(offset)
if attrtype in (IFA_ADDRESS, IFA_LOCAL, IFA_BROADCAST, IFA_ANYCAST, IFA_MULTICAST):
address = parse_address(af, buf[payload_offset:])
sys.stdout.write(" address: %s\n" %
format_address(af, address))
if len(address) is 0:
print_hex(buf[:offset+attrlen], payload_offset)
elif attrtype is IFA_CACHEINFO:
# in linux/if_addr.h
pref, valid, cstamp, tstamp = struct.unpack('IIII', buf[payload_offset:payload_offset+32])
sys.stdout.write(" pref lifetime %d, valid lifetime %d, creation time %d, update time %d\n" %
(pref, valid, cstamp, tstamp))
elif attrtype is IFA_LABEL:
# just a string representing the name of the interface
sys.stdout.write(" interface: %s\n" % buf[payload_offset:])
else:
print_hex(buf[:offset+attrlen], payload_offset)
offset += rta_align_length(attrlen)
return offset
def parse_neigh_message(buf, type):
# Message structure: ndmsg, (rtattr, address|cacheinfo)+
# from linux/neighbour.h
af, ifindex, states, flags, neightype = struct.unpack('BxxxiHBB', buf[:12])
sys.stdout.write (" Neighbour message (%s): AF %d, index %d, states %s, flags %s, neighbour type %d\n"
% (rtnl_msg_types[type], af, ifindex,
"|".join([nd_states[c] for c in nd_states.keys() if c&states]),
"|".join([nd_flags[c] for c in nd_flags.keys() if c&flags]),
neightype))
offset = 12
while rta_offset_ok(offset, len(buf)):
attrlen, attrtype = parse_rtattr(rtattr(buf,offset), nda_types)
payload_offset = rta_data_offset(offset)
if attrtype is NDA_DST:
address = parse_address(af, buf[payload_offset:])
sys.stdout.write(" destination: %s\n" %
format_address(af, address))
if len(address) is 0:
print_hex(buf[:offset+attrlen], payload_offset)
elif attrtype is NDA_LLADDR:
address = parse_lladdr(buf[payload_offset:offset + attrlen])
sys.stdout.write(" link-layer address: %s\n"
% (format_address(af, address)))
elif attrtype is NDA_CACHEINFO:
confirmed, used, updated, refcnt = struct.unpack('IIII', buf[payload_offset:payload_offset+32])
sys.stdout.write(" confirmed %d, used %d, update time %d, reference count %d\n" %
(confirmed, used, updated, refcnt))
elif attrtype is NDA_PROBES:
sys.stdout.write(" probes: %d\n"
% struct.unpack('I', buf[payload_offset:payload_offset+4]))
else:
print_hex(buf[:offset+attrlen], payload_offset)
offset += rta_align_length(attrlen)
return offset
def parse_route_message(buf, type):
# Message structure: rtmsg, (rtattr, address|cacheinfo)+
# from linux/rtnetlink.h
af, dst_len, src_len, tos, tableid, protocol, scope, rttype, flags = struct.unpack('BBBBBBBBI', buf[:12])
sys.stdout.write (" Route message (%s): AF %d, destination length %d, source length %d, TOS %d, tableid %d, protocol %s, scope %s, type %s, flags %s\n"
% (rtnl_msg_types[type], af,
dst_len, src_len, tos, tableid, rtm_protocol[protocol], rtm_scope[scope], rtm_type[rttype],
"|".join([rtm_flags[c] for c in rtm_flags.keys() if c&flags])))
offset = 12
while rta_offset_ok(offset, len(buf)):
# XXX parse attributes
attrlen, attrtype = parse_rtattr(rtattr(buf,offset), rta_types)
payload_offset = rta_data_offset(offset)
if attrtype is RTA_TABLE:
sys.stdout.write(" table: %d\n"
% struct.unpack('I', buf[payload_offset:payload_offset+4]))
elif attrtype in (RTA_DST, RTA_SRC, RTA_GATEWAY):
address = parse_address(af, buf[payload_offset:])
sys.stdout.write(" %s address: %s\n" % (rta_types[attrtype],
format_address(af, address)))
if len(address) is 0:
print_hex(buf[:offset+attrlen], payload_offset)
elif attrtype is RTA_METRICS:
# rtnetlink.h: RTM_METRICS --- array of struct rtattr with types of RTAX_*
metrics_offset = 0
while rta_offset_ok(metrics_offset, attrlen):
metric_len, metric_type = parse_rtattr(rtattr(buf, payload_offset + metrics_offset), rtax_metrics, True)
metricdata_offset = rta_data_offset(payload_offset + metrics_offset)
# XXX: are all metrics integers?
sys.stdout.write(" %s: %d\n" % (rtax_metrics[metric_type],
struct.unpack('I', buf[metricdata_offset:metricdata_offset+4])[0]))
metrics_offset += rta_align_length(metric_len)
elif attrtype is RTA_PRIORITY:
sys.stdout.write(" route priority: %d\n"
% struct.unpack('I', buf[payload_offset:payload_offset+4]))
elif attrtype is RTA_OIF:
sys.stdout.write(" oif: %d\n"
% struct.unpack('I', buf[payload_offset:payload_offset+4]))
elif attrtype is RTA_CACHEINFO:
if attrlen > 20:
# RTNETLINK_HAVE_PEERINFO is defined
sys.stdout.write(" clntref %d, last use %d, expiration %d, error %d, used %d, id %d, ts %d, tsage %d\n"
% struct.unpack('IIiIIIII', buf[payload_offset:payload_offset+32]))
else:
sys.stdout.write(" clntref %d, last use %d, expiration %d, error %d, used %d\n"
% struct.unpack('IIiII', buf[payload_offset:payload_offset+20]))
else:
print_hex(buf[:offset+attrlen], payload_offset)
offset += rta_align_length(attrlen)
return offset
def parse_rt_message(buf, type):
offset = 0
if type in (RTM_NEWLINK, RTM_DELLINK):
offset += parse_link_message(buf, type)
elif type in (RTM_NEWADDR, RTM_DELADDR):
offset += parse_addr_message(buf, type)
elif type in (RTM_NEWNEIGH, RTM_DELNEIGH):
offset += parse_neigh_message(buf, type)
elif type in (RTM_NEWROUTE, RTM_DELROUTE):
offset += parse_route_message(buf, type)
return offset
def parse_sockid(buf, af):
sport, dport, src, dst, intf, cookie1, cookie2 = struct.unpack(">HH16s16sIII", buf)
src = parse_address(af, src)
dst = parse_address(af, dst)
sys.stdout.write (" Socket identity: sport %d, dport %d, src addr %s, dst addr %s, interface %d, cookies %x %x\n" %
(sport, dport, format_address(af, src),
format_address(af, dst), intf, cookie1, cookie2))
def parse_diag_request(buf, type):
# Message structure: inet_diag_req (with sock_id)
# from linux/inet_diag.h
af, src_len, dst_len, ext = struct.unpack('BBBB', buf[:4])
sys.stdout.write (" Diag request (%s): AF %d, source length %d, destination length %d, extended information %d\n" %
(diag_types[type], af,
src_len, dst_len, ext))
sockid, states, dbs = struct.unpack('48sII', buf[4:60])
parse_sockid(sockid, af)
sys.stdout.write (" states %s, dbs %s\n" %
("|".join([sock_states[c] for c in sock_states.keys() if (1<<c)&states]),
"|".join([diag_dbs[c] for c in diag_dbs.keys() if c&dbs])))
offset = 60
return offset
def parse_diag_message(buf, type):
# Message structure: inet_diag_req (with sock_id)
# from linux/inet_diag.h
af, state, timer, retrans= struct.unpack('BBBB', buf[:4])
sys.stdout.write (" Diag message (%s): AF %d, state %s, timer %d, retrans %d\n" %
(diag_types[type], af,
"|".join([sock_states[c] for c in sock_states.keys() if (1<<c)&state]),
timer, retrans))
sockid, expires, rqueue, wqueue, uid, inode = struct.unpack('48sIIIII', buf[4:72])
parse_sockid(sockid, af)
sys.stdout.write (" expires %s, r/w queues %d/%d, uid %d, inode %d\n" % (expires, rqueue, wqueue, uid, inode))
offset = 72
# Extensions are pu inside rtattrs
while rta_offset_ok(offset, len(buf)):
attrlen, attrtype = parse_rtattr(rtattr(buf,offset), diag_extensions)
payload_offset = rta_data_offset(offset)
if attrtype is INET_DIAG_MEMINFO:
# struct inet_diag_meminfo
# from linux/inet_diag.h
rmem, wmem, fmem, tmem = struct.unpack("IIII",
buf[payload_offset:offset+attrlen])
sys.stdout.write (" read mem %d, write mem %d, f mem %d, t mem %d\n" %
(rmem, wmem, fmem, tmem))
elif attrtype is INET_DIAG_INFO:
# struct tcp_info
# from linux/tcp.h
tcp_info = struct.unpack("BBBBBBBIIIIIIIIIIIIIIIIIIIIIIII",
buf[payload_offset:offset+attrlen])
tcp_info = (sock_states[tcp_info[0]], tcp_ca_states[tcp_info[1]]) + tcp_info[2:5] + \
("|".join([tcpi_options[c] for c in tcpi_options.keys() if 1<<c&tcp_info[5]]),) \
+ tcp_info[6:]
sys.stdout.write(" state %s, ca_state %s, retransmits %d, probes %d, backoff %d, options %s, srscales %d, rto %d, ato %d, snd_mss %d, rcv_mss %d, unacked %d, sacked %d, lost %d, retrans %d, fackets %d, last_data_sent %d, last_ack_sent %d, last_data_recv %d, last_ack_recv %d, pmtu %d, rcv_sshthresh %d, rtt %d, rttvar %d, snd_sshthresh %d, snd_cwnd %d, advmss %d, reordering %d, rcv_rtt %d, rcv_space %d, total_retrans %d\n" %
tcp_info)
elif attrtype is INET_DIAG_VEGASINFO:
# struct tcpvegas_info
# from linux/inet_diag.h
enabled, rttcnt, rtt, minrtt = struct.unpack("IIII",
buf[payload_offset:offset+attrlen])
sys.stdout.write (" vegas enabled %d, rtt count %d, rtt %d, minrtt %d\n" %
(enabled, rttcnt, rtt, minrtt))
elif attrtype is INET_DIAG_CONG:
sys.stdout.write (" congestion control '%s'\n" %
buf[payload_offset:offset+attrlen])
else:
print_hex(buf[:offset+attrlen], payload_offset)
offset += rta_align_length(attrlen)
return offset
def parse_nl_message(buf, type):
status = struct.unpack('i', buf[:4])
errno = -status[0]
sys.stdout.write (" Netlink reply (%s)\n" % nlmsg_types[type])
if errno:
print " errno: %s" % errorcode[errno]
print " Old header:",
parse_message(buf[4:])
return len(buf)
def _parse_message(buf):
size, type, flags, seq, pid = struct.unpack('IHHII', buf[:16])
# XXX: Filter out non IPv6-related messages but keep unspec ones
#af = struct.unpack("B",buf[16:17])
#if af[0] not in (AF_UNSPEC, AF_INET6):
#return
print "size %d, type %s, flags %s (%d), seq %d, from PID %d" % \
(size, type,
"|".join(nlm_flags[c] for c in nlm_flags.keys() if c&flags),
flags, seq, pid)
offset = 16
try:
if type in rtnl_msg_types:
offset += parse_rt_message(buf[16:], type)
elif type in nlmsg_types:
offset += parse_nl_message(buf[16:], type)
# XXX: cascade to cactch TCPDIAG_GETSOCK and DCCPDIAG_GETSOCK
# which have the same values as RTNL* messages...
if offset == 16 and type in diag_types:
if NLM_F_REQUEST&flags:
offset += parse_diag_request(buf[16:], type)
else:
offset += parse_diag_message(buf[16:], type)
if offset < len(buf):
sys.stdout.write(" Padding/unparsed (%d/%d)\n" % (offset, len(buf)))
print_hex(buf,offset)
except struct.error, e:
print " TRUNCATED DATA: " + e.message
def parse_message(buf):
parsed = 0
while parsed < len(buf):
size = struct.unpack('I', buf[parsed:parsed+4])[0]
if size > len(buf)-parsed:
print " WARNING: provided size (%d) doesn't match buffer length (%d)" % (size, len(buf))
_parse_message(buf[parsed:parsed+size])
parsed += size
print
#NetlinkRequest = namedtuple('NetlinkRequest', 'length, type, flags, seq, srcpid, diagaf, srclen, dstlen, ext, states, dbs')
#NetlinkRequest.fmt=('IHHIIBBBBII')
class NetlinkInterface:
route_sock = None;
diag_sock = None
pid = None
groups = None
diag_seq = None
def __init__ (self):
self.route_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)
self.route_sock.bind((0,RTMGRP_LINK | RTMGRP_NEIGH |
RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE))
self.pid, self.groups = self.route_sock.getsockname()
self.diag_sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG)
self.diag_seq = 0
self.send_diag_req()
def __del__(self):
if self.route_sock:
self.route_sock.close()
if self.diag_sock:
self.diag_sock.close()
def send_diag_req(self):
for type in diag_types.keys():
print "SENDING (%s, seq %d):" % (diag_types[type], self.diag_seq),
# struct inet_diag_req from linux/inet_diag.h
# XXX: require as much extended information as possible
# padding is inet_diag_sockid
nlmsg = struct.pack("BBBB48xII",
AF_INET6, 0, 0, INET_DIAG_ALL_F, SS_ALL_F, DB_TCP)
# struct nlmsghdr: length (incl. nlh), type, flags, seq, pid
nlh = struct.pack("IHHII", len(nlmsg) + 4*4, type,
NLM_F_REQUEST|NLM_F_MATCH|NLM_F_ROOT, self.diag_seq, os.getpid())
# linux/netlink.h
# struct sockaddr_nl: AF, padding, PID, groups
## no need for iovec-based scatter/gather IO
# addr = struct.pack("HxxII", AF_NETLINK, 0, 0)
# msg = addr + nlh + nlmsg
msg = nlh + nlmsg
parse_message(msg)
self.diag_sock.sendall(msg)
self.diag_seq += 1
def dump(self):
while True:
has_data, awaits_data, has_error = select.select(
(self.route_sock, self.diag_sock),
(), (self.route_sock, self.diag_sock), 60)
for sock in has_data:
buf = sock.recv(65536)
print "RECEIVING:",
parse_message(buf)
for sock in has_error:
print sock, "HAS ERROR"
if __name__ == '__main__':
ni = NetlinkInterface()
ni.dump()