def subnet_equ(prf_a=None, prf_b=None, mask_a=None, mask_b=None): if prf_a is None or prf_b is None or mask_a is None or mask_b is None: return False if mask_a != mask_b: return False a = ip_to_bin(prf_a) & ip_to_bin(masklen2netmask(mask_a)) b = ip_to_bin(prf_b) & ip_to_bin(masklen2netmask(mask_b)) if a == b: return True else: return False
def action(self, packet): targetip = utils.bin_to_ip(packet.data.src) targetport = 137 nbns_response = packet.data.data.data nbns_response.op = 0x8500 # For each question, add an answer for query in nbns_response.qd: name = decode_name(query.name).rstrip() address = self.getAddress(name) if not address: out.debug("%s: Skipped Query from %s for %s" % (self.getName(), targetip, name), 0) continue answer = NS.RR() answer.name = query.name # We reinsert in encoded format answer.type = query.type answer.cls = query.cls answer.ttl = 120 # Not very long TTL answer.rlen = 6 answer.rdata = '\x00\x00' + utils.ip_to_bin(address) # 0x0000 is flags for Unique name + B-Node nbns_response.an.append(answer) nbns_response.qd = [] if len(nbns_response.an) == 0: return False # Response is a UDP packet with 137 source port and Query's IP+Port as destination sock = socket(AF_INET, SOCK_DGRAM) sock.bind(('0.0.0.0', targetport)) sock.sendto(str(nbns_response), (targetip, packet.data.data.sport)) sock.close() for answer in nbns_response.an: out.verbose("%s: \tResponse: %s - %s" % (self.getName(), decode_name(answer.name).rstrip(), utils.bin_to_ip(answer.rdata[2:]))) return True
def parseData(self, data): packet = dpkt.ethernet.Ethernet(data) # Skip packets sent from our machine if packet.dst == get_mac(self.interface[0]): return None # ARP if packet.type == dpkt.ethernet.ETH_TYPE_ARP: packet.data = dpkt.arp.ARP(str(packet.data)) # IPv4 elif packet.type == dpkt.ethernet.ETH_TYPE_IP: packet.data = dpkt.ip.IP(str(packet.data)) # UDP if packet.data.p == dpkt.ip.IP_PROTO_UDP: packet.data.data = dpkt.udp.UDP(str(packet.data.data)) # LLMNR (224.0.0.252:5355), same packet format as DNS if packet.data.dst == ip_to_bin("224.0.0.252") and packet.data.data.dport == 5355: packet.data.data.data = dpkt.dns.DNS(str(packet.data.data.data)) # Netbios Name Service (from 137 UDP to 137 UDP) if packet.data.data.dport == 137 and packet.data.data.dport == 137: packet.data.data.data = dpkt.netbios.NS(str(packet.data.data.data)) # TCP elif packet.data.p == dpkt.ip.IP_PROTO_TCP: packet.data.data = dpkt.tcp.TCP(str(packet.data.data)) return packet
def condition(self, packet): # Should be an IPv4 packet if packet.type != dpkt.ethernet.ETH_TYPE_IP: return False # Should be a UDP packet if packet.data.p != dpkt.ip.IP_PROTO_UDP: return False # Should have a 224.0.0.252:5355 destination if packet.data.dst != utils.ip_to_bin("224.0.0.252"): return False if packet.data.data.dport != 5355: return False # And is a LLMNR Request if packet.data.data.data.op & 0x8000 != 0: return False out.verbose("%s: LLMNR request from %s" % (self.getName(), utils.bin_to_ip(packet.data.src))) out.verbose("%s: \tQueries: %s" % (self.getName(), ' '.join([x.name for x in packet.data.data.data.qd]))) return True
def action(self, packet): targetip = utils.bin_to_ip(packet.data.src) targetport = 5355 llmnr_response = packet.data.data.data llmnr_response.op = 0x8000 # For each question, add an answer for query in llmnr_response.qd: address = self.getAddress(query.name, query.type) if not address: out.debug("%s: Skipped query from %s for %s" % (self.getName(), targetip, query.name), 0) continue answer = dpkt.dns.DNS.RR() answer.name = query.name answer.type = query.type answer.cls = query.cls answer.ttl = 30 if answer.type == dpkt.dns.DNS_A: answer.rlen = 4 answer.rdata = utils.ip_to_bin(address) elif answer.type == dpkt.dns.DNS_AAAA: answer.rlen = 16 answer.rdata = utils.ip6_to_bin(address) llmnr_response.an.append(answer) if len(llmnr_response.an) == 0: return False # Response is a UDP packet with 5355 source port and Query's source port # as destination port. sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind(('0.0.0.0', targetport)) sock.sendto(str(llmnr_response), (targetip, packet.data.data.sport)) sock.close() for answer in llmnr_response.an: if answer.type == dpkt.dns.DNS_A: out.verbose("%s: \tResponse: %s - %s" % (self.getName(), answer.name, utils.bin_to_ip(answer.rdata))) elif answer.type == dpkt.dns.DNS_AAAA: out.verbose("%s: \tResponse: %s - %s" % (self.getName(), answer.name, utils.bin_to_ip6(answer.rdata))) return True
def subnet_create_api(): """ Implementation Notes Creates a subnet on a network. Response Class (Status 201) Subnet { subnetId (string, optional): Subnet uuid. subnetName (string, optional): Subnet name, a user readable name. networkId (string, optional): Network uuid. cidr (string, optional): The CIDR of subnet. allocation_pools (Array[inline_model], optional): The start and end addresses for the allocation pools. gatewayIp (string, required): The gateway IP address. dnsNameservers (Array[string], optional): A list of DNS name servers for the subnet. } inline_model { start (string, optional): Start IP address. , end (string, optional): End IP address. } Parameters Subnet (body, required): Subnet description """ try: req = models.Subnet(request.json) req.validate() except Exception as e: return err_return('Parameter Invalid', 'ParameterInvalid', '', HTTP_BAD_REQUEST) try: if not req.network_id: return err_return('networkid is required', 'ParameterInvalid', '', HTTP_BAD_REQUEST) if not req.subnet_id: req_id = str(uuid.uuid4()) else: req_id = req.subnet_id sb_name = subnet_db_get_one('name', id=req_id) if sb_name: return err_return('id(%s) in use by %s' % (req_id, sb_name), 'ParameterInvalid', '', HTTP_BAD_REQUEST) if req.subnet_name: if len(req.subnet_name) > NAME_MAX_LEN: return err_return('Length of name must be less than 255', 'ParameterInvalid', '', HTTP_BAD_REQUEST) else: req.subnet_name = '' external = network_db_get_one('external', id=req.network_id) if external is None: return err_return("networkid does not exist", "ParameterInvalid", "", HTTP_BAD_REQUEST) if not req.dns_nameservers: req.dns_nameservers = [] if not req.allocation_pools: req.allocation_pools = [] allocation_pools = [] for all_pool in req.allocation_pools: allocation_pools.append(all_pool.to_primitive()) req.allocation_pools = allocation_pools for pool in req.allocation_pools: if ip_to_bin(pool['start']) > ip_to_bin(pool['end']): return err_return("end_ip must be more than start_ip", "IPRangeError", "", HTTP_BAD_REQUEST) if external == 0: if not req.cidr: return err_return('cidr is required', 'ParameterInvalid', '', HTTP_BAD_REQUEST) if not validate_cidr(req.cidr): return err_return('cidr invalid', 'ParameterInvalid', '', HTTP_BAD_REQUEST) if not req.gateway_ip: return err_return('gateway ip is required', 'ParameterInvalid', '', HTTP_BAD_REQUEST) vl2lcid = yynetworkid_to_lcvl2id(req.network_id) log.debug('vl2lcid=%s' % vl2lcid) nets = [{ "prefix": VFW_TOR_LINK_NET_PRE, "netmask": VFW_TOR_LINK_NET_MASK }] cidr = str(req.cidr).split('/') new_prf = cidr[0] new_mask = int(cidr[1]) subnets = get_subnets_by_network(req.network_id) for subnet in subnets: cidr = subnet['cidr'].split('/') old_prf = cidr[0] old_mask = int(cidr[1]) if subnet_equ(new_prf, old_prf, new_mask, old_mask): log.error('cidr is the same') return err_return('subnet already exist', 'ParameterInvalid', '', HTTP_BAD_REQUEST) nets.append({"prefix": old_prf, "netmask": old_mask}) nets.append({"prefix": new_prf, "netmask": new_mask}) log.debug('nets=%s' % nets) nw_name = network_db_get_one('name', id=req.network_id) payload = json.dumps({"name": nw_name, "nets": nets}) r = lcapi.patch(conf.livecloud_url + '/v1/vl2s/%s' % vl2lcid, data=payload) if r.status_code != HTTP_OK: return Response(json.dumps(NEUTRON_400)), HTTP_NOT_FOUND nets = r.json()['DATA']['NETS'] for net in nets: if subnet_equ(net['PREFIX'], new_prf, net['NETMASK'], new_mask): sb_lcuuid = net['LCUUID'] sb_idx = net['NET_INDEX'] break else: log.error('sb_lcuuid no found') sb_lcuuid = 'sb_lcuuid no found' sb_idx = -1 else: subnetid = subnet_db_get_one('id', network_id=req.network_id) if subnetid: return err_return('subnet(%s) already exists' % subnetid, 'Fail', '', HTTP_BAD_REQUEST) # ISP if not req.allocation_pools: return err_return('allocation_pools can not be empty', 'ParameterInvalid', '', HTTP_BAD_REQUEST) id = subnet_db_get_one('id', network_id=req.network_id) if id: return subnet_get(subnetid=id) lcuuid = network_db_get_one('lcuuid', id=req.network_id) isp = lc_vl2_db_get_one('isp', lcuuid=lcuuid) items = lc_ip_res_db_get_all(req='ip, netmask, gateway, userid', isp=isp) if not items: return err_return("No ISP IP found", "BadRequest", "Please add ISP IP to system first", HTTP_BAD_REQUEST) req.gateway_ip = items[0]['gateway'] req.cidr = ip_mask_to_cidr(items[0]['ip'], items[0]['netmask']) isp_all_ips = [] ip_to_userid = {} for it in items: isp_all_ips.append(it['ip']) ip_to_userid[it['ip']] = it['userid'] req_ips = alloc_pools_to_ip_list(req.allocation_pools) for req_ip in req_ips: if req_ip not in isp_all_ips: return err_return("%s does not exist" % req_ip, "IPInvalid", "", HTTP_BAD_REQUEST) if ip_to_userid[req_ip] != 0: return err_return("%s in use" % req_ip, "IPInUse", "", HTTP_BAD_REQUEST) sb_lcuuid = str(uuid.uuid4()) sb_idx = -1 sql = ("INSERT INTO neutron_subnets " "VALUES('%s','%s','%s','%s','%s','%s','%s','%s',%d)" % (req_id, req.subnet_name, req.network_id, req.cidr, json.dumps(req.allocation_pools), req.gateway_ip, json.dumps(req.dns_nameservers), sb_lcuuid, sb_idx)) log.debug('add subnet sql=%s' % sql) with MySQLdb.connect(**DB_INFO) as cursor: cursor.execute(sql) if external: sql = "UPDATE ip_resource_v2_2 SET userid=%s WHERE ip in ('-1'," for req_ip in req_ips: sql += "'%s'," % req_ip sql = sql[:-1] sql += ")" log.debug('sql=%s' % sql) with MySQLdb.connect(**LCDB_INFO) as cursor: cursor.execute(sql, conf.livecloud_userid) resp, code = subnet_get(subnetid=req_id) return resp, HTTP_CREATED except Exception as e: log.error(e) return Response(json.dumps(NEUTRON_500)), HTTP_INTERNAL_SERVER_ERROR
def subnet_put_api(subnetid=None): """ Implementation Notes Updates existing subnet. Response Class (Status 200) Subnet { subnetId (string, optional): Subnet uuid. subnetName (string, optional): Subnet name, a user readable name. networkId (string, optional): Network uuid. cidr (string, optional): The CIDR of subnet. allocation_pools (Array[inline_model], optional): The start and end addresses for the allocation pools. gatewayIp (string, optional): The gateway IP address. dnsNameservers (Array[string], optional): A list of DNS name servers for the subnet. } inline_model { start (string, optional): Start IP address. , end (string, optional): End IP address. } Parameters subnetId (string, optional): The subnet uuid to act on Subnet (body, required): Subnet description """ try: if not subnetid: return err_return('subnetId is required', "ParameterInvalid", "", HTTP_BAD_REQUEST) db_subnet = subnet_db_get_one('*', id=subnetid) if not db_subnet: return err_return('subnetId does not exist', "ParameterInvalid", "", HTTP_NOT_FOUND) cidr = db_subnet['cidr'] try: req = models.Subnet(request.json) req.validate() except Exception as e: log.error(e) return err_return('Parameter Invalid', "ParameterInvalid", "", HTTP_BAD_REQUEST) with MySQLdb.connect(**DB_INFO) as cursor: if req.subnet_name is not None: if len(req.subnet_name) > NAME_MAX_LEN: return err_return('Length of name must be less than 255', 'ParameterInvalid', '', HTTP_BAD_REQUEST) sql = "UPDATE neutron_subnets SET name=%s WHERE id=%s" cursor.execute(sql, (req.subnet_name, subnetid)) if req.dns_nameservers is not None: sql = ("UPDATE neutron_subnets SET " "dns_nameservers=%s WHERE id=%s") cursor.execute(sql, (json.dumps(req.dns_nameservers), subnetid)) if req.allocation_pools is not None: allocation_pools = [] for all_pool in req.allocation_pools: allocation_pools.append(all_pool.to_primitive()) req.allocation_pools = allocation_pools for pool in req.allocation_pools: if ip_to_bin(pool['start']) > ip_to_bin(pool['end']): return err_return("end_ip must be more than start_ip", "IPRangeError", "", HTTP_BAD_REQUEST) networkid = subnetid_to_networkid(subnetid) db_network = network_db_get_one('*', id=networkid) external = db_network['external'] log.debug('external=%s' % external) if external: if req.allocation_pools is not None: old_alloc_pools = json.loads(db_subnet['allocation_pools']) old_alloc_ips = alloc_pools_to_ip_list(old_alloc_pools) new_alloc_ips = alloc_pools_to_ip_list(req.allocation_pools) tmp_nips = copy.deepcopy(new_alloc_ips) for new_ip in tmp_nips: if new_ip in old_alloc_ips: new_alloc_ips.remove(new_ip) old_alloc_ips.remove(new_ip) isp = lc_vl2_db_get_one('isp', lcuuid=db_network['lcuuid']) items = lc_ip_res_db_get_all(req='ip, userid, vifid', isp=isp) isp_all_ips = [] ip_to_userid = {} ip_to_vifid = {} for it in items: isp_all_ips.append(it['ip']) ip_to_userid[it['ip']] = it['userid'] ip_to_vifid[it['ip']] = it['vifid'] for new_alloc_ip in new_alloc_ips: if new_alloc_ip not in isp_all_ips: return err_return("%s invalid" % new_alloc_ip, "IPInvalid", "", HTTP_BAD_REQUEST) if ip_to_userid[new_alloc_ip] != 0: return err_return("%s in use" % new_alloc_ip, "IPInUse", "", HTTP_BAD_REQUEST) for old_alloc_ip in old_alloc_ips: if ip_to_vifid[old_alloc_ip] != 0: return err_return("%s in use" % old_alloc_ip, "IPInUse", "", HTTP_BAD_REQUEST) sql = ("UPDATE neutron_subnets SET allocation_pools='%s' " "WHERE id='%s'" % (json.dumps(req.allocation_pools), subnetid)) with MySQLdb.connect(**DB_INFO) as cursor: cursor.execute(sql) sql = ("UPDATE ip_resource_v2_2 SET userid=0 " "WHERE ip in ('-1',") for ip in old_alloc_ips: sql += "'%s'," % ip sql = sql[:-1] sql += ")" sql2 = ("UPDATE ip_resource_v2_2 SET userid=%s " "WHERE ip in ('-1',") for ip in new_alloc_ips: sql2 += "'%s'," % ip sql2 = sql2[:-1] sql2 += ")" with MySQLdb.connect(**LCDB_INFO) as cursor: cursor.execute(sql) cursor.execute(sql2, conf.livecloud_userid) return subnet_get(subnetid=subnetid) if req.gateway_ip is not None: with MySQLdb.connect(**DB_INFO) as cursor: sql = "UPDATE neutron_subnets SET gateway_ip=%s WHERE id=%s" cursor.execute(sql, (req.gateway_ip, subnetid)) log.debug('old_cidr=%s, new_cidr=%s' % (cidr, req.cidr)) if req.cidr and cidr != req.cidr: vl2lcid = yynetworkid_to_lcvl2id(networkid) nets = [{ "prefix": VFW_TOR_LINK_NET_PRE, "netmask": VFW_TOR_LINK_NET_MASK }] subnets = get_subnets_by_network(networkid) for subnet in subnets: if str(subnet['id']) == subnetid: continue cidr = subnet['cidr'].split('/') nets.append({"prefix": cidr[0], "netmask": int(cidr[1])}) cidr = str(req.cidr).split('/') log.debug('netmask=%s' % cidr[1]) nets.append({"prefix": cidr[0], "netmask": int(cidr[1])}) nw_name = network_db_get_one('name', id=networkid) payload = json.dumps({"name": nw_name, "nets": nets}) log.debug('patch vl2 data=%s' % payload) r = lcapi.patch(conf.livecloud_url + '/v1/vl2s/%s' % vl2lcid, data=payload) if r.status_code != HTTP_OK: err = r.json()['DESCRIPTION'] log.error(err) return err_return(err, 'Fail', '', HTTP_BAD_REQUEST) nets = r.json()['DATA']['NETS'] for net in nets: if subnet_equ(net['PREFIX'], cidr[0], net['NETMASK'], int(cidr[1])): sb_lcuuid = net['LCUUID'] sb_idx = net['NET_INDEX'] break else: log.error('sb_lcuuid no found') return Response(json.dumps(NEUTRON_500)), \ HTTP_INTERNAL_SERVER_ERROR if req.allocation_pools is None: req.allocation_pools = [] else: req.cidr = db_subnet['cidr'] sb_lcuuid = db_subnet['lcuuid'] sb_idx = db_subnet['net_idx'] if req.allocation_pools is None: return subnet_get(subnetid=subnetid) new_alloc_ips = alloc_pools_to_ip_list(req.allocation_pools) vl2id = lc_vl2_db_get_one('id', lcuuid=sb_lcuuid) used_ips = lc_vif_ip_db_get_all('ip', vl2id=vl2id, net_index=sb_idx) for used_ip in used_ips: ip = used_ip['ip'] if ip not in new_alloc_ips: return err_return('used ip(%s) not in alloc pool' % ip, 'ParameterInvalid', '', HTTP_BAD_REQUEST) sql = ("UPDATE neutron_subnets SET cidr='%s', " "allocation_pools='%s', lcuuid='%s', net_idx=%s " "WHERE id='%s'" % (req.cidr, json.dumps( req.allocation_pools), sb_lcuuid, sb_idx, subnetid)) log.debug('sql=%s' % sql) with MySQLdb.connect(**DB_INFO) as cursor: cursor.execute(sql) return subnet_get(subnetid=subnetid) except Exception as e: log.error(e) return Response(json.dumps(NEUTRON_500)), HTTP_INTERNAL_SERVER_ERROR