xbase-util 0.0.8__tar.gz → 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,8 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: xbase_util
3
- Version: 0.0.8
3
+ Version: 0.1.0
4
4
  Summary: 网络安全基础工具
5
+ Home-page: https://gitee.com/jimonik/xbase_util.git
5
6
  Author: xyt
6
7
  Author-email: 2506564278@qq.com
7
8
  License: <MIT License>
@@ -3,13 +3,14 @@ from distutils.core import setup
3
3
  from setuptools import find_packages
4
4
 
5
5
  setup(name="xbase_util",
6
- version="0.0.8",
6
+ version="0.1.0",
7
7
  description="网络安全基础工具",
8
8
  long_description="包含提取,预测,训练的基础工具",
9
9
  author="xyt",
10
10
  author_email="2506564278@qq.com",
11
11
  license="<MIT License>",
12
12
  packages=find_packages(),
13
+ url="https://gitee.com/jimonik/xbase_util.git",
13
14
  install_requires=[
14
15
  ],
15
16
  zip_safe=False,
@@ -0,0 +1,29 @@
1
+ import os.path
2
+
3
+
4
+ class EsDb:
5
+ def __init__(self, req):
6
+ self.req = req
7
+ self.internals = {}
8
+ print("初始化:Elasticsearch DB")
9
+
10
+ def get_file_by_file_id(self, node, num, prefix=None):
11
+ key = f'{node}!{num}'
12
+ if key in self.internals:
13
+ return self.internals[key]
14
+ res = self.req.search_file(f"{node}-{num}")
15
+ hits = res['hits']['hits']
16
+ if len(hits) > 0:
17
+ self.internals[key] = hits[0]['_source']
18
+ file = hits[0]['_source']
19
+ if prefix is None:
20
+ return file
21
+ prefix_res = prefix
22
+ if not prefix.endswith('/'):
23
+ prefix_res = f"{prefix}/"
24
+ origin_path = file['name']
25
+ basename = os.path.basename(origin_path)
26
+ result_path = f"{prefix_res}{basename}"
27
+ file['name'] = result_path
28
+ return file
29
+ return None
@@ -0,0 +1,26 @@
1
+ import requests
2
+
3
+
4
+ class EsReq:
5
+ def __init__(self, url,timeout=120):
6
+ self.es_url = url
7
+ self.timeout = timeout
8
+ print("初始化自定义es请求类")
9
+
10
+ def clear_all_scroll(self):
11
+ return requests.delete(self.es_url + "/_search/scroll", timeout=self.timeout, json={'scroll_id': '_all'})
12
+
13
+ def search(self, body, scroll):
14
+ requests.post(self.es_url + "/_search/scroll", data=body, timeout=self.timeout, json={'scroll_id': scroll})
15
+
16
+ def start_scroll(self, exp, scroll):
17
+ return requests.post(self.es_url + "/_search/scroll", timeout=self.timeout,
18
+ json=exp)
19
+
20
+ def scroll_by_id(self, scroll_id, scroll):
21
+ return requests.post(self.es_url + "/_search/scroll", timeout=self.timeout,
22
+ json={'scroll_id': scroll_id, 'scroll': scroll})
23
+
24
+ def search_file(self, id):
25
+ return requests.get(f"{self.es_url}/arkime_files_v30/_search", timeout=self.timeout,
26
+ json={"query": {"term": {"_id": id}}})
@@ -0,0 +1,161 @@
1
+ import json
2
+ import re
3
+ import traceback
4
+ from urllib.parse import unquote
5
+
6
+ import pandas as pd
7
+
8
+
9
+ def handle_uri(data):
10
+ print(f"处理URI:{len(data)}")
11
+ # 定义正则表达式,确保精确匹配各种攻击特征
12
+ regex_patterns = {
13
+ "sql": re.compile(
14
+ r"\b(select|union|insert|update|delete|drop|--|#| or |' or '|information_schema|database\(\)|version\(\))\b",
15
+ re.IGNORECASE),
16
+ "xss": re.compile(r"(<script\b|javascript:|onload=|onclick=|<iframe\b|src=)", re.IGNORECASE),
17
+ "cmd": re.compile(
18
+ r"(/etc/passwd\b|/etc/shadow\b|;|&&|\||\$\(.+\)|\bcurl\b|\bwget\b|\bexec\b|\bsystem\b|cmd=|proc/self/environ)",
19
+ re.IGNORECASE),
20
+ "path": re.compile(r"(\.\./|\.\.%2f|\.\.%5c|\.\.\\|\.\.;|%2f%2e%2e%2f)", re.IGNORECASE),
21
+ "redirect": re.compile(r"(redirect=|url=|next=|redirect_uri=|redirect:|RedirectTo=)", re.IGNORECASE),
22
+ "danger": re.compile(
23
+ r"(%3C|%3E|%27|%22|%00|%2F|%5C|%3B|%7C|%28|%29|%20|%3D|%3A|%3F|%26|%23|%2B|%25|file://|<foo|xmlns:|/etc/passwd|windows/win\.ini)",
24
+ re.IGNORECASE),
25
+ "suspicious_ext": re.compile(
26
+ r"\.(exe|sh|py|pl|bak|php5|jspx|bat|cmd|pif|js|vbs|vbe|sct|ini|inf|tmp|swp|jar|java|class|ps1)\b",
27
+ re.IGNORECASE)
28
+ }
29
+
30
+ # 定义多层解码函数,确保完全解码 URI
31
+ def fully_decode_uri(uri):
32
+ try:
33
+ decoded_uri = str(uri)
34
+ for _ in range(3): # 尝试多次解码嵌套的编码
35
+ decoded_uri = unquote(decoded_uri)
36
+ return decoded_uri
37
+ except Exception as e:
38
+ return uri
39
+
40
+ def process_row(row):
41
+ uris = row['http.uri']
42
+ if not isinstance(uris, list):
43
+ try:
44
+ uris = json.loads(uris)
45
+ if not isinstance(uris, list):
46
+ uris = [str(uris)]
47
+ except Exception:
48
+ uris = [str(uris)]
49
+ try:
50
+ decoded_uris = [fully_decode_uri(uri) for uri in uris]
51
+ except Exception as e:
52
+ traceback.print_exc()
53
+ exit(0)
54
+
55
+
56
+ # 初始化统计变量
57
+ param_count = 0
58
+ path_depth = 0
59
+ param_lengths = []
60
+ feature_flags = {key: False for key in regex_patterns.keys()}
61
+
62
+ # 遍历解码后的 URI
63
+ for uri in decoded_uris:
64
+ param_count += uri.count('&') + 1
65
+ path_depth += uri.count('/')
66
+
67
+ # 提取参数长度
68
+ if '?' in uri:
69
+ params = uri.split('?', 1)[-1].split('&')
70
+ for param in params:
71
+ if '=' in param:
72
+ _, value = param.split('=', 1)
73
+ param_lengths.append(len(value))
74
+
75
+ # 检查正则匹配特征
76
+ for key, pattern in regex_patterns.items():
77
+ if pattern.search(uri):
78
+ feature_flags[key] = True
79
+
80
+ # 计算参数长度的统计值
81
+ avg_length = sum(param_lengths) / len(param_lengths) if param_lengths else 0
82
+ max_length = max(param_lengths) if param_lengths else 0
83
+
84
+ # 创建返回结果字典
85
+ result = {
86
+ "URI_FEATURES_EXTRA_param_count": param_count,
87
+ "URI_FEATURES_EXTRA_path_depth": path_depth,
88
+ "URI_FEATURES_EXTRA_param_length_avg": avg_length,
89
+ "URI_FEATURES_EXTRA_param_length_max": max_length,
90
+ }
91
+
92
+ # 添加特征标志到结果
93
+ for key, value in feature_flags.items():
94
+ result[f"URI_FEATURES_EXTRA_contains_{key}"] = value
95
+
96
+ return result
97
+ feature_data = data.progress_apply(process_row, axis=1, result_type="expand")
98
+ data = pd.concat([data, feature_data], axis=1)
99
+ return data
100
+
101
+
102
+ def handle_ua(data):
103
+ print("处理UA")
104
+ data['http.useragent'] = data['http.useragent'].fillna('').astype(str)
105
+ # 处理换行符及多余空格
106
+ data['http.useragent'] = data['http.useragent'].str.replace(r'\s+', ' ', regex=True)
107
+ # 常见攻击的 User-Agent 字符串匹配模式,忽略大小写
108
+ attack_patterns = '|'.join([
109
+ r"\bselect\b", r"\bunion\b", r"\binsert\b", r"\bupdate\b", r"\bdelete\b", r"\bdrop\b", r"--", r"#", r" or ",
110
+ r"' or '",
111
+ r"information_schema", r"database\(\)", r"version\(\)", # SQL注入相关
112
+ r"<script>", r"javascript:", r"onload=", r"onclick=", r"<iframe>", r"src=", # XSS相关
113
+ r"/etc/passwd", r"/etc/shadow", r"\&\&", r"\|", r"\$\(\)", r"exec", r"system", # 命令执行相关
114
+ r"\.\./", r"\.\.%2f", r"\.\.%5c", r"%c0%af", r"%252e%252e%252f", # 路径遍历
115
+ r"\.php", r"\.asp", r"\.jsp", r"\.exe", r"\.sh", r"\.py", r"\.pl", # 文件扩展名
116
+ r"redirect=", r"url=", r"next=", # 重定向
117
+ r"%3C", r"%3E", r"%27", r"%22", r"%00", r"%2F", r"%5C", r"%3B", r"%7C", r"%2E", r"%28", r"%29", # 编码
118
+ r'Googlebot', r'Bingbot', r'Slurp', r'curl', r'wget', r'Nmap',
119
+ r'SQLMap', r'Nikto', r'Dirbuster', r'python-requests', r'Apache-HttpClient',
120
+ r'Postman', r'Burp Suite', r'Fuzzing', r'nessus'
121
+ ])
122
+ # 企业客户端 User-Agent 模式
123
+ enterprise_patterns = '|'.join([
124
+ r'MicroMessenger', r'wxwork', r'QQ/', r'QQBrowser', r'Alipay', r'UCWEB'
125
+ ])
126
+ # 批量检查是否为攻击的 User-Agent,忽略大小写
127
+ data['UserAgent_is_attack'] = data['http.useragent'].str.contains(attack_patterns, case=False, regex=True)
128
+ # 批量检查是否为企业客户端,忽略大小写
129
+ data['UserAgent_is_enterprise'] = data['http.useragent'].str.contains(enterprise_patterns, case=False)
130
+ # 提取浏览器和版本
131
+ data['UserAgent_browser'] = data['http.useragent'].str.extract(r'(Chrome|Firefox|Safari|MSIE|Edge|Opera|Trident)',
132
+ expand=False, flags=re.IGNORECASE).fillna("Unknown")
133
+ data['UserAgent_browser_version'] = data['http.useragent'].str.extract(
134
+ r'Chrome/([\d\.]+)|Firefox/([\d\.]+)|Version/([\d\.]+).*Safari|MSIE ([\d\.]+)|Edge/([\d\.]+)|Opera/([\d\.]+)|Trident/([\d\.]+)',
135
+ expand=False, flags=re.IGNORECASE).bfill(axis=1).fillna("Unknown").iloc[:, 0]
136
+ # 提取操作系统和版本
137
+ os_info = data['http.useragent'].str.extract(
138
+ r'(Windows NT [\d\.]+|Mac OS X [\d_\.]+|Linux|Android [\d\.]+|iOS [\d_\.]+|Ubuntu|Debian|CentOS|Red Hat)',
139
+ expand=False, flags=re.IGNORECASE)
140
+ data['UserAgent_os'] = os_info.str.extract(r'(Windows|Mac OS X|Linux|Android|iOS|Ubuntu|Debian|CentOS|Red Hat)',
141
+ expand=False, flags=re.IGNORECASE).fillna("Unknown")
142
+ data['UserAgent_os_version'] = os_info.str.extract(r'([\d\._]+)', expand=False).fillna("Unknown")
143
+ # 提取设备类型,忽略大小写
144
+ data['UserAgent_device_type'] = data['http.useragent'].str.contains('mobile|android|iphone', case=False).map(
145
+ {True: 'Mobile', False: 'Desktop'})
146
+ # 提取硬件平台,增加对 x64 的匹配
147
+ data['UserAgent_platform'] = data['http.useragent'].str.extract(r'(x86|x86_64|arm|arm64|x64)', expand=False,
148
+ flags=re.IGNORECASE).fillna('Unknown')
149
+ # 判断是否为爬虫,忽略大小写
150
+ data['UserAgent_is_bot'] = data['http.useragent'].str.contains('bot|crawler|spider|slurp|curl|wget|httpclient',
151
+ case=False)
152
+ # 提取语言偏好(如果存在),忽略大小写
153
+ data['UserAgent_language'] = data['http.useragent'].str.extract(r'\b([a-z]{2}-[A-Z]{2})\b', expand=False,
154
+ flags=re.IGNORECASE).fillna("Unknown")
155
+ # 统计 User-Agent 中的特殊字符个数
156
+ data['UserAgent_special_char_count'] = data['http.useragent'].progress_apply(
157
+ lambda x: len(re.findall(r'[!@#$%^&*\'=:|{}]', x, flags=re.IGNORECASE)))
158
+ # 更新 UserAgent_is_unknown 的计算逻辑
159
+ data['UserAgent_is_unknown'] = data[['UserAgent_browser', 'UserAgent_os', 'UserAgent_platform']].isna().any(
160
+ axis=1).fillna("Unknown")
161
+ return data
@@ -0,0 +1,247 @@
1
+ import math
2
+ import os
3
+ import struct
4
+ import time
5
+ import zlib
6
+ from datetime import datetime
7
+
8
+ from Crypto.Cipher import AES
9
+ from zstandard import ZstdDecompressor
10
+
11
+
12
+ def fix_pos(pos, packetPosEncoding):
13
+ if pos is None or len(pos) == 0:
14
+ return
15
+ if packetPosEncoding == "gap0":
16
+ last = 0
17
+ lastgap = 0
18
+ for i, pos_item in enumerate(pos):
19
+ if pos[i] < 0:
20
+ last = 0
21
+ else:
22
+ if pos[i] == 0:
23
+ pos[i] = last + lastgap
24
+ else:
25
+ lastgap = pos[i]
26
+ pos[i] += last
27
+ last = pos[i]
28
+
29
+
30
+ def group_numbers(nums):
31
+ result = []
32
+ for num in nums:
33
+ if num < 0:
34
+ result.append([num])
35
+ elif result:
36
+ result[-1].append(num)
37
+ return result
38
+
39
+
40
+ def decompress_streaming(compressed_data, id, fro):
41
+ try:
42
+ decompressor = ZstdDecompressor()
43
+ with decompressor.stream_reader(compressed_data) as reader:
44
+ decompressed_data = reader.read()
45
+ return decompressed_data
46
+ except Exception as e:
47
+ print(f"解码错误:{e} {id}")
48
+ return bytearray()
49
+
50
+
51
+ def read_header(param_map, id):
52
+ shortHeader = None
53
+ headBuffer = os.read(param_map['fd'], 64)
54
+ if param_map['encoding'] == 'aes-256-ctr':
55
+ if 'iv' in param_map:
56
+ param_map['iv'][12:16] = struct.pack('>I', 0)
57
+ headBuffer = bytearray(
58
+ AES.new(param_map['encKey'], AES.MODE_CTR, nonce=param_map['iv']).decrypt(bytes(headBuffer)))
59
+ else:
60
+ print("读取头部信息失败,iv向量为空")
61
+ elif param_map['encoding'] == 'xor-2048':
62
+ for i in range(len(headBuffer)):
63
+ headBuffer[i] ^= param_map['encKey'][i % 256]
64
+ if param_map['uncompressedBits']:
65
+ if param_map['compression'] == 'gzip':
66
+ headBuffer = zlib.decompress(bytes(headBuffer), zlib.MAX_WBITS | 16)
67
+ elif param_map['compression'] == 'zstd':
68
+ headBuffer = decompress_streaming(headBuffer, id, "header")
69
+ headBuffer = headBuffer[:24]
70
+ magic = struct.unpack('<I', headBuffer[:4])[0]
71
+ bigEndian = (magic == 0xd4c3b2a1 or magic == 0x4d3cb2a1)
72
+ # nanosecond = (magic == 0xa1b23c4d or magic == 0x4d3cb2a1)
73
+ if not bigEndian and magic not in {0xa1b2c3d4, 0xa1b23c4d, 0xa1b2c3d5}:
74
+ corrupt = True
75
+ # os.close(param_map['fd'])
76
+ raise ValueError("Corrupt PCAP header")
77
+ if magic == 0xa1b2c3d5:
78
+ shortHeader = struct.unpack('<I', headBuffer[8:12])[0]
79
+ headBuffer[0] = 0xd4 # Reset header to normal
80
+ linkType = struct.unpack('>I' if bigEndian else '<I', headBuffer[20:24])[0]
81
+ return headBuffer, shortHeader, bigEndian
82
+
83
+
84
+ def create_decipher(pos, param_map):
85
+ param_map['iv'][12:16] = struct.pack('>I', pos)
86
+ return AES.new(param_map['encKey'], AES.MODE_CTR, nonce=param_map['iv'])
87
+
88
+
89
+ def read_packet_internal(pos_arg, hp_len_arg, param_map, id):
90
+ pos = pos_arg
91
+ hp_len = hp_len_arg
92
+ if hp_len == -1:
93
+ if param_map['compression'] == "zstd":
94
+ hp_len = param_map['uncompressedBitsSize']
95
+ else:
96
+ hp_len = 2048
97
+ inside_offset = 0
98
+ if param_map['uncompressedBits']:
99
+ inside_offset = pos & param_map['uncompressedBitsSize'] - 1
100
+ pos = math.floor(pos / param_map['uncompressedBitsSize'])
101
+ pos_offset = 0
102
+ if param_map['encoding'] == 'aes-256-ctr':
103
+ pos_offset = pos % 16
104
+ pos = pos - pos_offset
105
+ elif param_map['encoding'] == 'xor-2048':
106
+ pos_offset = pos % 256
107
+ pos = pos - pos_offset
108
+
109
+ hp_len = 256 * math.ceil((hp_len + inside_offset + pos_offset) / 256)
110
+ buffer = bytearray(hp_len)
111
+ os.lseek(param_map['fd'], pos, os.SEEK_SET)
112
+ read_buffer = os.read(param_map['fd'], len(buffer))
113
+ if len(read_buffer) - pos_offset < 16:
114
+ return None
115
+ if param_map['encoding'] == 'aes-256-ctr':
116
+ decipher = create_decipher(pos // 16, param_map)
117
+ read_buffer = bytearray(decipher.decrypt(read_buffer))[pos_offset:]
118
+ elif param_map['encoding'] == 'xor-2048':
119
+ read_buffer = bytearray(b ^ param_map['encKey'][i % 256] for i, b in enumerate(read_buffer))[pos_offset:]
120
+ if param_map['uncompressedBits']:
121
+ try:
122
+ if param_map['compression'] == 'gzip':
123
+ read_buffer = zlib.decompress(read_buffer, zlib.MAX_WBITS | 16)
124
+ elif param_map['compression'] == 'zstd':
125
+ read_buffer = decompress_streaming(read_buffer, id, "packet")
126
+ except Exception as e:
127
+ print(f"PCAP uncompress issue: {pos} {len(buffer)} {read_buffer} {e}")
128
+ return None
129
+ if inside_offset:
130
+ read_buffer = read_buffer[inside_offset:]
131
+ header_len = 16 if param_map['shortHeader'] is None else 6
132
+ if len(read_buffer) < header_len:
133
+ if hp_len_arg == -1 and param_map['compression'] == 'zstd':
134
+ return read_packet_internal(pos_arg, param_map['uncompressedBitsSize'] * 2, param_map, id)
135
+ print(f"Not enough data {len(read_buffer)} for header {header_len}")
136
+ return None
137
+ packet_len = struct.unpack('>I' if param_map['bigEndian'] else '<I', read_buffer[8:12])[
138
+ 0] if param_map['shortHeader'] is None else \
139
+ struct.unpack('>H' if param_map['bigEndian'] else '<H', read_buffer[:2])[0]
140
+ if packet_len < 0 or packet_len > 0xffff:
141
+ return None
142
+ if header_len + packet_len <= len(read_buffer):
143
+ if param_map['shortHeader'] is not None:
144
+ t = struct.unpack('<I', read_buffer[2:6])[0]
145
+ sec = (t >> 20) + param_map['shortHeader']
146
+ usec = t & 0xfffff
147
+ new_buffer = bytearray(16 + packet_len)
148
+ struct.pack_into('<I', new_buffer, 0, sec)
149
+ struct.pack_into('<I', new_buffer, 4, usec)
150
+ struct.pack_into('<I', new_buffer, 8, packet_len)
151
+ struct.pack_into('<I', new_buffer, 12, packet_len)
152
+ new_buffer[16:] = read_buffer[6:packet_len + 6]
153
+ return new_buffer
154
+ return read_buffer[:header_len + packet_len]
155
+
156
+ if hp_len_arg != -1:
157
+ return None
158
+
159
+ return read_packet_internal(pos_arg, 16 + packet_len, param_map, id)
160
+
161
+
162
+ def read_packet(pos, param_map, id):
163
+ if 'fd' not in param_map or not param_map['fd']:
164
+ time.sleep(0.01)
165
+ return read_packet(pos, param_map['fd'], id)
166
+ return read_packet_internal(pos, -1, param_map, id)
167
+
168
+
169
+ def get_file_and_read_pos(id, file, pos_list):
170
+ filename = file['name']
171
+ if not os.path.isfile(filename):
172
+ print(f"文件不存在:{filename}")
173
+ return None
174
+ encoding = file.get('encoding', 'normal')
175
+ encKey = None
176
+ iv = None
177
+ compression = None
178
+ if 'dek' in file:
179
+ dek = bytes.fromhex(file['dek'])
180
+ encKey = AES.new(file['kek'].encode(), AES.MODE_CBC).decrypt(dek)
181
+
182
+ if 'uncompressedBits' in file:
183
+ uncompressedBits = file['uncompressedBits']
184
+ uncompressedBitsSize = 2 ** uncompressedBits
185
+ compression = 'gzip'
186
+ else:
187
+ uncompressedBits = None
188
+ uncompressedBitsSize = 0
189
+ if 'compression' in file:
190
+ compression = file['compression']
191
+
192
+ if 'iv' in file:
193
+ iv_ = bytes.fromhex(file['iv'])
194
+ iv = bytearray(16)
195
+ iv[:len(iv_)] = iv_
196
+ fd = os.open(filename, os.O_RDONLY)
197
+ param_map = {
198
+ "fd": fd,
199
+ "encoding": encoding,
200
+ "iv": iv,
201
+ "encKey": encKey,
202
+ "uncompressedBits": uncompressedBits,
203
+ "compression": compression,
204
+ "uncompressedBitsSize": uncompressedBitsSize
205
+ }
206
+ res = bytearray()
207
+ headBuffer, shortHeader, bigEndian = read_header(param_map, id)
208
+ res.extend(headBuffer)
209
+ param_map['shortHeader'] = shortHeader
210
+ param_map['bigEndian'] = bigEndian
211
+ # _________________________________
212
+ byte_array = bytearray(0xfffe)
213
+ next_packet = 0
214
+ b_offset = 0
215
+ packets = {}
216
+ i = 0
217
+ for pos in pos_list:
218
+ packet_bytes = read_packet(pos, param_map, id)
219
+ if not packet_bytes:
220
+ continue
221
+ packets[i] = packet_bytes
222
+ while next_packet in packets:
223
+ buffer = packets[next_packet]
224
+ del packets[next_packet]
225
+ next_packet = next_packet + 1
226
+ if b_offset + len(buffer) > len(byte_array):
227
+ res.extend(byte_array[:b_offset])
228
+ b_offset = 0
229
+ byte_array = bytearray(0xfffe)
230
+ byte_array[b_offset:b_offset + len(buffer)] = buffer
231
+ b_offset += len(buffer)
232
+ i = i + 1
233
+ os.close(fd)
234
+ res.extend(byte_array[:b_offset])
235
+ return res
236
+
237
+
238
+ def process_session_id_disk_simple(id, node, packet_pos, esdb, pcap_path_prefix):
239
+ packetPos = packet_pos
240
+ file = esdb.get_file_by_file_id(node=node, num=abs(packetPos[0]),
241
+ prefix=None if pcap_path_prefix == "origin" else pcap_path_prefix)
242
+ if file is None:
243
+ return None
244
+ fix_pos(packetPos, file['packetPosEncoding'])
245
+ pos_list = group_numbers(packetPos)[0]
246
+ pos_list.pop(0)
247
+ return get_file_and_read_pos(id, file, pos_list)
@@ -1,7 +1,8 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: xbase-util
3
- Version: 0.0.8
3
+ Version: 0.1.0
4
4
  Summary: 网络安全基础工具
5
+ Home-page: https://gitee.com/jimonik/xbase_util.git
5
6
  Author: xyt
6
7
  Author-email: 2506564278@qq.com
7
8
  License: <MIT License>
@@ -1,6 +1,10 @@
1
1
  README.md
2
2
  setup.py
3
3
  xbase_util/__init__.py
4
+ xbase_util/es_db_util.py
5
+ xbase_util/esreq.py
6
+ xbase_util/handle_features_util.py
7
+ xbase_util/pcap_util.py
4
8
  xbase_util/xbase_util.py
5
9
  xbase_util.egg-info/PKG-INFO
6
10
  xbase_util.egg-info/SOURCES.txt
File without changes
File without changes