Log In
New Account

HomeMy PageProject TreeProject OpeningsOlivier Mehani's work at Imara
SummaryActivitySCMFiles
SCM
[mehani] View of /canso/trunk/tools/netlink.py
[mehani] / canso / trunk / tools / netlink.py Repository:
ViewVC logotype

View of /canso/trunk/tools/netlink.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1360 - (download) (as text) (annotate)
Fri Sep 4 09:09:40 2009 UTC (2 years, 3 months ago) by mehani
File size: 35698 byte(s)
[canso] Cleanup removing unused variable in netlik tool.

#!/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()

root@gforge.inria.fr
ViewVC Help
Powered by ViewVC 1.0.0