#!/usr/bin/evn python
# -*- coding:utf-8 -*-

import os
import time
import sys
import configparser

sys.path.append("../..")

from CapturePacketByProces_Android.CapturePacketByProces import *


# 界面操作类
class InterfaceOperation():
    def __init__(self, simulator_ip_port):
        self._simulator_ip_port = simulator_ip_port
        # 获取像素
        command_str = "adb -s " + self._simulator_ip_port + " shell wm size"
        size_str = os.popen(command_str).read()
        # Physical size: 900x1600
        wm_size_str_1 = size_str.split(' ')
        # 900x1600
        wm_size_str_2 = wm_size_str_1[2].split('x')
        time.sleep(3)
        self._pixel_x = wm_size_str_2[0]
        self._pixel_y = wm_size_str_2[1]

    # 打开VPN
    def Connect_VPN(self):
        x = int(self._pixel_x) * 0.5
        y = int(self._pixel_y) * 0.85
        print(self._pixel_x, self._pixel_y)
        command_str = "adb -s " + self._simulator_ip_port + " shell input tap " + str(round(x)) + " " + str(round(y))
        os.system(command_str)
        time.sleep(1)
        return
    
    # 关闭VPN
    def DisConnect_VPN(self):
        x = int(self._pixel_x) * 0.5
        y = int(self._pixel_y) * 0.85
        command_str = "adb -s " + self._simulator_ip_port + " shell input tap " + str(round(x)) + " " + str(round(y))
        os.system(command_str)
        time.sleep(1)
        return


from scapy.all import rdpcap, TCP, IP


def extract_rst_ips(input_pcap):
    """
    从输入PCAP文件中提取包含TCP RST包的IP地址。

    :param input_pcap: 输入PCAP文件的路径
    :return: 包含TCP RST包的源IP地址和目的IP地址的集合
    """
    # 读取输入PCAP文件
    packets = rdpcap(input_pcap)

    # 创建一个集合，用于存储提取的IP地址
    rst_ips = set()

    # 遍历所有包，检查是否为TCP RST包
    for pkt in packets:
        if TCP in pkt and pkt[TCP].flags & 0x04:  # 检查是否有RST标志
            if IP in pkt:
                rst_ips.add(pkt[IP].src)
                rst_ips.add(pkt[IP].dst)

    return rst_ips


import requests
import json


def send_put_request(ipaddr):
    url = 'http://192.168.44.29/v1/policy/object/16190'     
    # 要将ip替换为实际系统的ip，16190要替换为实际的IP对象的ID
    headers = {
        'Accept': '*/*',
        'Content-Type': 'application/json',
        'Authorization': '1ca0350bc499a208a0edadb74d76a0ee&1&'    
        # BJ环境特殊为：1ca0350bc499a208a0edadb74d76a0ee&1&，其余环境均为：aa2bdec5518ad131f71944b13ce5c298&1&
    }

    data = {
        "vsys_id": 1,     
        "id": 16190,    # 要替换为实际的IP对象的ID
        "return_data": 1,
        "object": {
            "id": 16190,   # 要替换为实际的IP对象的ID
            "name": "Thunder_VPN_Test_auto",    # 要替换为实际的IP对象的名字
            "type": "ip",
            "sub_type": "ip",
            # "icon_color": "",
            # "description": "",
            "member": {
                "type": "item",
                "item_num": 3,
                "items": [
                    {
                        "op": "add",
                        "id": None,
                        # "temporaryId": 1715958788103,
                        "ip": {
                            "port": "0-65535",
                            "ip_format": "ip",
                            "ip_address": ipaddr,
                            "addr_type": 4
                        },
                        "line": 0
                    }
                ]
            },
            # "uuid": "1545a7d0-144f-11ef-b458-fe73137d8c09",
            # "data_origin": 0,
            "is_enabled": 1,
            "reference_count": 1,
            "metric_query": {
                "last_reset_start_time": None
            },
            # "seq_no": 0,
            "vsys_id": 1,
            # "is_builtin": 0,
            # "is_shared": 0,
            # "created_time": "2024-05-17T13:12:16Z",
            # "created_by": 6,
            # # "last_modified_time": "2024-05-17T14:45:38Z",
            # "last_modified_by": 6
        }
    }

    response = requests.put(url, headers=headers, json=data)
    '''
    result
    192.168.1.206
    {
      "code" : 200,
      "msg" : "Success",
      "data" : null,
      "success" : true
    }
    '''
    return ipaddr, response


if __name__=="__main__":
    # read config file
    if os.path.exists('./config.ini'):
        file = './config.ini'     
    else:
        print("没有找到配置文件 !! \n   请将位置文件config.ini放置在脚本同级路径")
        sys.exit()
    con = configparser.ConfigParser()                                                           # 实例化读取文件对象
    con.read(file, encoding='utf-8')                                                            # 读取文件

    adb_items = con.items('adb')                                                                # 指定读取的段
    adb_items = dict(adb_items)                                                                 # 将读取的段转成字典
    app_package_name = adb_items.get("app_package_name")                                        # 配置app包名用于启动和停止app。获取UserID等
    app_class_name = adb_items.get("app_class_name")                                            # 配置app类名用于启动和停止app
    simulator_ip_port = adb_items.get("simulator_ip_port")                                      # 配置模拟器连接 防止出现连接错误
    network_cord_name = adb_items.get("network_cord_name")
    capture_packet_mode = int(adb_items.get("capture_packet_mode"))

    # 配置输出文件路径及文件名
    output_items = con.items('output')
    output_items = dict(output_items)
    run_log_file_path_name = output_items.get("run_log_file_path") + '\\'  + output_items.get("run_log_file_name") 
    pcap_src_file_path = output_items.get("pcap_src_file_path")
    if not os.path.exists(pcap_src_file_path):
        os.makedirs(pcap_src_file_path)
    pcap_parse_file_path = output_items.get("pcap_parse_file_path")
    if not os.path.exists(pcap_parse_file_path):
        os.makedirs(pcap_parse_file_path)
    
    run_items = con.items('run')
    run_items = dict(run_items)
    
    if os.path.exists(run_log_file_path_name) and len(open(run_log_file_path_name,'r').readlines()) >= 1:
        with open(run_log_file_path_name, 'r') as f:  
            lines = f.readlines()
            execution_start_id = int(lines[-1].split('|')[0])
            execution_start_id += 1
    else:
        # 配置循环执行启动编号
        execution_start_id = int(run_items.get("execution_start_id"))                            
    
    # 配置循环执行终止编号  
    execution_end_id  = int(run_items.get("execution_end_id"))                                     
    execution_end_id += 1
    execution_sleep_time = int(run_items.get("execution_sleep_time"))

    # 打开输出日志文件
    file_handle = open(run_log_file_path_name, "a")                                                       

    # 初始化抓包对象 
    capture_packet = CapturePacket(app_package_name, app_class_name, simulator_ip_port, capture_packet_mode)    
    # 初始化界面操作对象
    interface_operation = InterfaceOperation(simulator_ip_port)   

    # 循环执行抓包     
    for pcap_file_ID in range(execution_start_id, execution_end_id):                                                    
        write_line = ""
        # 开启抓包
        capture_packet.StartCapturePacket(str(pcap_file_ID), pcap_src_file_path, network_cord_name)
        time.sleep(3)  
        # 启动APP                                                                                 
        capture_packet.StartAPP()
        time.sleep(20)

        # 获取连接VPN之前的公网IP                                                                        
        public_ip_src = capture_packet.GetPublicIP()
        print("public_ip_src : ", public_ip_src)
        if public_ip_src == '' :
            print("模拟器联网失败 请检查模拟器网络连接")
            break

        # 获取开始连接VPN的时间戳
        current_time = time.ctime()  
        write_line += str(pcap_file_ID) + '|' + public_ip_src + '|' + current_time + '|'
        # 开始连接VPN
        interface_operation.Connect_VPN()
        # 等待VPN连接
        time.sleep(20)     

        # 获取连接VPN之后的公网IP 
        public_ip_vpn = capture_packet.GetPublicIP()
        print("public_ip_vpn : ", public_ip_vpn)
        time.sleep(20) 
        # 判断连接VPN之后获取到的公网IP是否与连接VPN之前一致，若一致，则说明连接失败。
        if public_ip_src == public_ip_vpn or public_ip_vpn == '':
            write_line += "Connection failed" + '\n'  
            file_handle.write(write_line)
            file_handle.flush()
            # 取消VPN连接
            interface_operation.DisConnect_VPN()
            time.sleep(3)
            # 关闭APP
            capture_packet.StopAPP()
            time.sleep(3)
            # 停止抓包并导出pcap文件                                                              
            capture_packet.StopCapturePacket(str(pcap_file_ID), pcap_src_file_path)    
            continue
        else:
            # 访问其他网址 产生流量
            capture_packet.CurlFile("www.youtube.com")
            capture_packet.CurlFile("www.youtube.com")
            capture_packet.CurlFile("www.youtube.com")
            capture_packet.CurlFile("www.youtube.com")
            capture_packet.WgetFile("www.people.com")
            # time.sleep(execution_sleep_time)      
            # 断开VPN连接                                                               
            interface_operation.DisConnect_VPN()
            # 获取断开连接VPN的时间戳
            current_time = time.ctime()

            write_line += current_time + '|'  
            write_line += public_ip_vpn + '|'

            # 获取公网IP所在的国家及城市
            if public_ip_vpn != '':
                location = capture_packet.GetLocation(public_ip_vpn)
                print("location : ", location)
                write_line += location['country'] + ':' + location['city'] + '\n'  
            else:
                write_line += "No location found" + '\n'     
            # send_put_request(public_ip_vpn)
    
        # 关闭APP
        # time.sleep(3)    
        capture_packet.StopAPP()
        time.sleep(3)  
        # 停止抓包并导出pcap文件    
        capture_packet.StopCapturePacket(str(pcap_file_ID), pcap_src_file_path)     
        time.sleep(3)
        # 写日志文件
        output_pcap = "simulator_uid_" + capture_packet._userID + "_" + str(pcap_file_ID) +".pcap"

        file_handle.write(write_line)
        file_handle.flush()
    # 抓包对象 析构
    del capture_packet
    file_handle.close()