bin.monitor
Main execution, handle arguments, init each instances
1#! /usr/bin/env python3.9 2""" 3Main execution, handle arguments, init each instances 4""" 5 6import os 7import sys 8import signal 9import bgpout 10import argparse 11import urllib.request 12from configobj import ConfigObj 13from bgpfilter import BGPFilter 14from Databases.database import BGPDatabases 15 16DEFAULT_GEOOPEN_URL = ( 17 "https://cra.circl.lu/opendata/geo-open/mmdb-country-asn/latest.mmdb" 18) 19 20# define bin/ as default workdir 21os.chdir(os.path.dirname(os.path.abspath(__file__))) 22 23 24def asnPrefixFromFile(file): 25 """Read prefixes and AS numbers from files 26 27 Args: 28 file (File): File that contains as numbers and prefixes 29 30 Returns: 31 Dict: Dictionnary with prefix_list, asn_list, match type 32 """ 33 res = {"asn_list": [], "prefix_list": [], "match": "more"} 34 35 for line in file.read().splitlines(): 36 if len(line) > 0: 37 splitted_line = line.split() 38 if splitted_line[0] == ">": 39 res["prefix_list"].append(splitted_line[1]) 40 elif splitted_line[0] == "AS": 41 res["asn_list"].append(splitted_line[1]) 42 elif splitted_line[0] == "MATCH": 43 res["match"] = splitted_line[1] 44 return res 45 46 47if __name__ == "__main__": 48 parser = argparse.ArgumentParser( 49 description="Tool for BGP filtering and monitoring", 50 allow_abbrev=True, 51 formatter_class=argparse.RawTextHelpFormatter, 52 ) 53 parser.add_argument("-v", "--version", action="version", version="%(prog)s 1.0") 54 parser.add_argument( 55 "--verbose", action="store_true", help="Print BGP records in console" 56 ) 57 58 parser.add_argument( 59 "--filter_list", 60 type=argparse.FileType("r"), 61 nargs="?", 62 help=( 63 "Use separated file to define list of prefixes and/or AS Numbers.\n Check" 64 " etc/filter_list.cfg.sample for file format" 65 ), 66 metavar="<path>", 67 ) 68 69 parser.add_argument( 70 "--config", 71 default="../etc/config.cfg", 72 help="Use different config file", 73 metavar="<path>", 74 ) 75 76 parser.add_argument( 77 "-jo", 78 "--json_output", 79 nargs="?", 80 type=argparse.FileType("w+"), 81 help=( 82 "File in which to display JSON output.\n If not set, default sys.stdout" 83 " will be used." 84 ), 85 metavar="<path>", 86 ) 87 88 parser.add_argument( 89 "-cf", 90 "--country_filter", 91 nargs="+", 92 help="Filter using specified country codes.", 93 metavar="<country code>", 94 ) 95 parser.add_argument( 96 "-af", 97 "--asn_filter", 98 nargs="+", 99 help=( 100 "Filter using specified AS number list, skip a record if its AS-source is" 101 " not one of specified AS numbers.\n Use _ symbol for negation" 102 ), 103 metavar="<AS number>", 104 ) 105 106 parser.add_argument( 107 "-ip", 108 "--ipversion", 109 choices=["4", "6"], 110 help="Filter specific ip address type. ipv4 or ipv6", 111 metavar="<version>", 112 ) 113 114 parser.add_argument( 115 "-pf", 116 "--prefix_filter", 117 nargs="+", 118 help=( 119 "Filter using specified prefix list, CIDR format: ip/subnet.\n Example:" 120 " 130.0.192.0/21,130.0.100.0/21" 121 ), 122 metavar="<prefix>", 123 ) 124 125 parser.add_argument( 126 "--match", 127 default="more", 128 choices=["more", "less", "exact", "any"], 129 help=( 130 "Type of match ->" 131 "exact: Exact match\n" 132 "more: Exact match or more specific (Contained by one of the prefixes)\n" 133 "less: Exact match or less specific (Contain one of the prefixes).\n" 134 "Default: more" 135 ), 136 ) 137 138 parser.add_argument( 139 "-p", 140 "--project", 141 default="ris", 142 choices=["ris", "routeviews"], 143 help="Project name", 144 ) 145 146 parser.add_argument( 147 "-c", 148 "--collectors", 149 nargs="+", 150 help=( 151 "Collectors. For complete list of collectors, see" 152 " https://bgpstream.caida.org/data" 153 ), 154 metavar="<collector>", 155 ) 156 157 parser.add_argument( 158 "-r", 159 "--record", 160 action="store_true", 161 help=( 162 "Retrieve records in the interval --until_time and --f-time arguments" 163 " (which are required)" 164 ), 165 ) 166 parser.add_argument( 167 "--start", 168 help=( 169 "Beginning of the interval.\n -> Timestamp format : YYYY-MM-DD hh:mm:ss.\n" 170 " Example: 2022-01-01 10:00:00" 171 ), 172 metavar="<begin>", 173 ) 174 parser.add_argument( 175 "--stop", 176 help=( 177 "End of the interval.\n -> Timestamp format : YYYY-MM-DD hh:mm:ss.\n " 178 " Example: 2022-01-01 10:10:00" 179 ), 180 metavar="<end>", 181 ) 182 183 parser.add_argument( 184 "-id", 185 "--input_data", 186 type=str, 187 help="Retrieve data from a single file instead of a broker.", 188 metavar="<path>", 189 ) 190 191 parser.add_argument( 192 "-ir", 193 "--input_record_type", 194 choices=["upd", "rib"], 195 default="upd", 196 help=( 197 "Type of records contained in input_data file.\n Can be rib (Routing" 198 " Information Base) or upd (Updates eg. Anoun/Withdr).\n Default: upd" 199 ), 200 ) 201 202 parser.add_argument( 203 "-if", 204 "--input_file_format", 205 choices=["mrt", "bmp", "ris-live"], 206 default="mrt", 207 help="input data type format. ris-live is avaible for updates only", 208 ) 209 210 parser.add_argument( 211 "--expected_result", 212 "-expected", 213 nargs="?", 214 type=argparse.FileType("r"), 215 metavar="<path>", 216 help="Check that the result is the same as the expected result", 217 ) 218 219 args = parser.parse_args() 220 if args.record and (args.from_time is None or args.until_time is None): 221 parser.error("--record requires --from_time and --until_time.") 222 223 if args.input_data and ( 224 args.input_file_format is None or args.input_record_type is None 225 ): 226 parser.error( 227 "--input_data requires --input_file_format and --input_record_type." 228 ) 229 if args.expected_result is not None and args.json_output is None: 230 parser.error("--expected_result requires --json_output") 231 232 # config 233 if os.path.isfile(args.config): 234 config = ConfigObj(args.config) 235 else: 236 raise FileNotFoundError(f"[-] No conf file found at {args.config}") 237 238 # BGPStream filter 239 filter = BGPFilter() 240 241 filter.project = args.project # ris / routeviews 242 filter.collectors = args.collectors # there are many collectors 243 filter.countries_filter = args.country_filter # Country codes 244 filter.ipversion = args.ipversion # 4 / 6 245 246 filter.record_mode(args.record, args.start, args.stop) 247 if args.input_data: 248 filter.data_source( 249 args.input_record_type, args.input_file_format, args.input_data 250 ) 251 252 if "geo-open" in config: 253 url = config["geo-open"] or DEFAULT_GEOOPEN_URL # if "download_url" 254 print("Downloading latest Geo Open Database", file=sys.stderr) 255 urllib.request.urlretrieve( 256 config["geo-open"]["download_url"], "../geo-open/latest.mmdb" 257 ) 258 259 filter.country_file = config["geo-open"]["path"] 260 261 if args.filter_list is not None: 262 res = asnPrefixFromFile(args.filter_list) 263 filter.prefix_filter = ( 264 res["prefix_list"] + (args.prefix_filter or []), 265 args.match, 266 ) 267 filter.asn_filter = res["asn_list"] + (args.asn_filter or []) 268 else: 269 filter.asn_filter = args.asn_filter # asn list 270 filter.prefix_filter = (args.prefix_filter, args.match) 271 272 # Output 273 bout = bgpout.BGPOut() 274 bout.json_out = args.json_output 275 bout.expected_result = args.expected_result 276 bout.verbose = args.verbose 277 bout.databases = BGPDatabases(config["databases"]) 278 279 filter.out = bout 280 281 # end of program 282 def stop(x, y): 283 filter.stop() 284 285 signal.signal(signal.SIGINT, stop) 286 filter.start() 287 filter.stop()
def
asnPrefixFromFile(file):
25def asnPrefixFromFile(file): 26 """Read prefixes and AS numbers from files 27 28 Args: 29 file (File): File that contains as numbers and prefixes 30 31 Returns: 32 Dict: Dictionnary with prefix_list, asn_list, match type 33 """ 34 res = {"asn_list": [], "prefix_list": [], "match": "more"} 35 36 for line in file.read().splitlines(): 37 if len(line) > 0: 38 splitted_line = line.split() 39 if splitted_line[0] == ">": 40 res["prefix_list"].append(splitted_line[1]) 41 elif splitted_line[0] == "AS": 42 res["asn_list"].append(splitted_line[1]) 43 elif splitted_line[0] == "MATCH": 44 res["match"] = splitted_line[1] 45 return res
Read prefixes and AS numbers from files
Args: file (File): File that contains as numbers and prefixes
Returns: Dict: Dictionnary with prefix_list, asn_list, match type