1#!/usr/bin/python3 2# 3# Copyright 2017 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17"""Generic netlink interface to TCP metrics.""" 18 19from socket import * # pylint: disable=wildcard-import 20import struct 21 22import binascii 23import cstruct 24import genetlink 25import net_test 26import netlink 27 28 29### TCP metrics constants. See include/uapi/linux/tcp_metrics.h. 30# Family name and version 31TCP_METRICS_GENL_NAME = "tcp_metrics" 32TCP_METRICS_GENL_VERSION = 1 33 34# Message types. 35TCP_METRICS_CMD_GET = 1 36TCP_METRICS_CMD_DEL = 2 37 38# Attributes. 39TCP_METRICS_ATTR_UNSPEC = 0 40TCP_METRICS_ATTR_ADDR_IPV4 = 1 41TCP_METRICS_ATTR_ADDR_IPV6 = 2 42TCP_METRICS_ATTR_AGE = 3 43TCP_METRICS_ATTR_TW_TSVAL = 4 44TCP_METRICS_ATTR_TW_TS_STAMP = 5 45TCP_METRICS_ATTR_VALS = 6 46TCP_METRICS_ATTR_FOPEN_MSS = 7 47TCP_METRICS_ATTR_FOPEN_SYN_DROPS = 8 48TCP_METRICS_ATTR_FOPEN_SYN_DROP_TS = 9 49TCP_METRICS_ATTR_FOPEN_COOKIE = 10 50TCP_METRICS_ATTR_SADDR_IPV4 = 11 51TCP_METRICS_ATTR_SADDR_IPV6 = 12 52TCP_METRICS_ATTR_PAD = 13 53 54 55class TcpMetrics(genetlink.GenericNetlink): 56 57 NL_DEBUG = ["ALL"] 58 59 def __init__(self): 60 super(TcpMetrics, self).__init__() 61 # Generic netlink family IDs are dynamically assigned. Find ours. 62 ctrl = genetlink.GenericNetlinkControl() 63 self.family = ctrl.GetFamily(TCP_METRICS_GENL_NAME) 64 65 def _Decode(self, command, msg, nla_type, nla_data, nested): 66 """Decodes TCP metrics netlink attributes to human-readable format.""" 67 68 name = self._GetConstantName(__name__, nla_type, "TCP_METRICS_ATTR_") 69 70 if name in ["TCP_METRICS_ATTR_ADDR_IPV4", "TCP_METRICS_ATTR_SADDR_IPV4"]: 71 data = inet_ntop(AF_INET, nla_data) 72 elif name in ["TCP_METRICS_ATTR_ADDR_IPV6", "TCP_METRICS_ATTR_SADDR_IPV6"]: 73 data = inet_ntop(AF_INET6, nla_data) 74 elif name in ["TCP_METRICS_ATTR_AGE"]: 75 data = struct.unpack("=Q", nla_data)[0] 76 elif name in ["TCP_METRICS_ATTR_TW_TSVAL", "TCP_METRICS_ATTR_TW_TS_STAMP"]: 77 data = struct.unpack("=I", nla_data)[0] 78 elif name == "TCP_METRICS_ATTR_FOPEN_MSS": 79 data = struct.unpack("=H", nla_data)[0] 80 elif name == "TCP_METRICS_ATTR_FOPEN_COOKIE": 81 data = nla_data 82 else: 83 data = binascii.hexlify(nla_data) 84 85 return name, data 86 87 def MaybeDebugCommand(self, command, unused_flags, data): 88 if "ALL" not in self.NL_DEBUG and command not in self.NL_DEBUG: 89 return 90 parsed = self._ParseNLMsg(data, genetlink.Genlmsghdr) 91 92 def _NlAttrSaddr(self, address): 93 if ":" not in address: 94 family = AF_INET 95 nla_type = TCP_METRICS_ATTR_SADDR_IPV4 96 else: 97 family = AF_INET6 98 nla_type = TCP_METRICS_ATTR_SADDR_IPV6 99 return self._NlAttrIPAddress(nla_type, family, address) 100 101 def _NlAttrTcpMetricsAddr(self, address, is_source): 102 version = net_test.GetAddressVersion(address) 103 family = net_test.GetAddressFamily(version) 104 if version == 5: 105 address = address.replace("::ffff:", "") 106 nla_name = "TCP_METRICS_ATTR_%s_IPV%d" % ( 107 "SADDR" if is_source else "ADDR", version) 108 nla_type = globals()[nla_name] 109 return self._NlAttrIPAddress(nla_type, family, address) 110 111 def _NlAttrAddr(self, address): 112 return self._NlAttrTcpMetricsAddr(address, False) 113 114 def _NlAttrSaddr(self, address): 115 return self._NlAttrTcpMetricsAddr(address, True) 116 117 def DumpMetrics(self): 118 """Dumps all TCP metrics.""" 119 return self._Dump(self.family, TCP_METRICS_CMD_GET, 1) 120 121 def GetMetrics(self, saddr, daddr): 122 """Returns TCP metrics for the specified src/dst pair.""" 123 data = self._NlAttrSaddr(saddr) + self._NlAttrAddr(daddr) 124 self._SendCommand(self.family, TCP_METRICS_CMD_GET, 1, data, 125 netlink.NLM_F_REQUEST) 126 hdr, attrs = self._GetMsg(genetlink.Genlmsghdr) 127 return attrs 128 129 def DelMetrics(self, saddr, daddr): 130 """Deletes TCP metrics for the specified src/dst pair.""" 131 data = self._NlAttrSaddr(saddr) + self._NlAttrAddr(daddr) 132 self._SendCommand(self.family, TCP_METRICS_CMD_DEL, 1, data, 133 netlink.NLM_F_REQUEST) 134 135 136if __name__ == "__main__": 137 t = TcpMetrics() 138 print(t.DumpMetrics()) 139