// // MainViewModel.swift // naiyoup // // Created by C Auto on 2021/8/2. // import Foundation import SwiftyUserDefaults import Combine //# Shadowsocks //SS = ss, 1.2.3.4, 8485, encrypt-method=chacha20-ietf-poly1305, password=123456 //Proxy = trojan, server.com, 443, password=123456 //EXTERNAL, site:cn, Direct //EXTERNAL, mmdb:cn, Direct //trace //debug let conf = """ [General] loglevel = debug tun-fd = REPLACE-ME-WITH-THE-FD dns-server = 223.5.5.5,8.8.8.8 always-fake-ip=* routing-domain-resolve = true [Proxy] Direct = direct Proxy = ssproxzy [Rule] site mmdb FINAL, Proxy """ //[Host] //proxy_host let conf_tro = """ [General] loglevel = trace dns-server = 223.5.5.5, 114.114.114.114 tun-fd = REPLACE-ME-WITH-THE-FD always-fake-ip=* routing-domain-resolve = true [Proxy] Direct = direct Proxy = ssproxzy [Rule] site mmdb FINAL, Proxy [Host] proxy_host """ class MainViewModel: ObservableObject { static let main = MainViewModel() @Published var vpnstatus = "未连接" @Published var serviceOpen = false @Published var authting = false var serverip = "" var password = "" var port = 0 var encrypt = "" var route : Bool = false var type = "shadowsocks" var sni = "" var ip:String? = nil var status: VPNStatus { didSet(o) { updateConnect() } } required init() { self.status = VPNHelper.shared.vpnStatus NotificationCenter.default.addObserver(self,selector: #selector(onVPNStatusChanged), name: NSNotification.Name(rawValue: kProxyServiceVPNStatusNotification), object: nil) } deinit { NotificationCenter.default.removeObserver(self) } @objc func onVPNStatusChanged(){ self.status = VPNHelper.shared.vpnStatus } func updateConnect() { switch status { case .connecting: break case .on: self.vpnstatus = "点击断开" self.serviceOpen = true break case .disconnecting: break case .off: self.vpnstatus = "未连接" self.serviceOpen = false break } guard let bundleAppGroup = Bundle.main.infoDictionary?["appGroup"] as? String else { fatalError("The application must contain appGroup in Info.plist file") } let name = bundleAppGroup print("打印值\(String(describing: name))") } func GetLoginModel() -> LoginModel? { if let loginModel = Defaults[\.loginModel] { return JsonUtil.LoginjsonToModel(loginModel, LoginModel.self) } return nil } func GetAuthNode(nodel:NodelModel?,success:@escaping Success,completion: ((_ error: Error?)-> Void)?) { self.vpnstatus = "开始验证" self.authting = true NetworkApi.shared.Auth { nodelmodel in if nodelmodel == nil { self.vpnstatus = "验证错误,没有获取到节点" self.authting = false } else{ self.vpnstatus = "完成验证" self.authting = false if nodel == nil { self.serverip = nodelmodel?.host ?? "" self.port = nodelmodel?.port ?? 0 self.encrypt = nodelmodel?.method ?? "" self.password = nodelmodel?.passwd ?? "" self.type = nodelmodel?.type ?? "shadowsocks" self.sni = nodelmodel?.sni ?? "" self.ip = nodelmodel?.ip success(nodelmodel?.name ?? "智能选线") } else { self.serverip = nodel?.host ?? "" self.port = nodel?.port ?? 0 self.encrypt = nodel?.method ?? "" self.password = nodel?.passwd ?? "" self.type = nodel?.type ?? "shadowsocks" self.sni = nodel?.sni ?? "" self.ip = nodel?.ip success(nodel?.name ?? "智能选线") } self.openService{ e in completion?(e) } } } failure: { err in self.vpnstatus = "验证错误\(err)" self.authting = false } } // 域名解析 func getIPAddress(domainName: String) -> String { var result = "" let host = CFHostCreateWithName(nil,domainName as CFString).takeRetainedValue() CFHostStartInfoResolution(host, .addresses, nil) var success: DarwinBoolean = false if let addresses = CFHostGetAddressing(host, &success)?.takeUnretainedValue() as NSArray?, let theAddress = addresses.firstObject as? NSData { var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST)) if getnameinfo(theAddress.bytes.assumingMemoryBound(to: sockaddr.self), socklen_t(theAddress.length), &hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 { let numAddress = String(cString: hostname) result = numAddress print(numAddress) } } return result } func openService(completion: ((_ error: Error?)-> Void)?) { // guard (self.activingEndpoint != nil) else { // completion?(NSError(domain: "ErrorDomain", code: -1, userInfo: ["error" : "没有激活服务节点"])) // return // } // let configData = try? JSONEncoder().encode(self.v2rayConfig) // guard configData != nil else { // completion?(NSError(domain: "ErrorDomain", code: -1, userInfo: ["error" : "配置错误"])) // return // } guard let bundleAppGroup = Bundle.main.infoDictionary?["appGroup"] as? String else { //fatalError("The application must contain appGroup in Info.plist file") completion?(NSError(domain: "ErrorDomain", code: -1, userInfo: ["error" : "appGroup没有获取到"])) return } var conftmp = "" //let serverIP = PacketTunnelMessage.getIPAddress(domainName: "") if (self.type == "shadowsocks") { let ss = "ss , \(self.serverip) , \(self.port) , encrypt-method=\(self.encrypt) , password=\(self.password)" conftmp = conf.replacingOccurrences(of: "ssproxzy", with: String(ss)) } else if(self.type == "trojan") { if(self.sni == ""){ self.sni = self.serverip } //Trojan = trojan, 4.3.2.1, 443, password=123456, sni=www.domain.com //Proxy = trojan, 1.2.3.4, 443, password=123456, ws=true, ws-path=/abc, sni=www.domain.com //, sni=\(self.sni) let trojan = "trojan,\(self.serverip),\(self.port),password=\(self.password), sni=\(self.sni)" let con = conf_tro.replacingOccurrences(of: "ssproxzy", with: String(trojan)) self.serverip = self.ip ?? getIPAddress(domainName: self.serverip) let host = "\(self.sni) = \(self.serverip)" //proxy_host conftmp = con.replacingOccurrences(of: "proxy_host", with: String(host)) } if self.route { //EXTERNAL, site:cn, Direct conftmp = conftmp.replacingOccurrences(of: "site", with: String("EXTERNAL, site:cn, Direct")) conftmp = conftmp.replacingOccurrences(of: "mmdb", with: String("EXTERNAL, mmdb:cn, Direct")) } else { conftmp = conftmp.replacingOccurrences(of: "site", with: String("EXTERNAL, site:cn, Proxy")) conftmp = conftmp.replacingOccurrences(of: "mmdb", with: String("EXTERNAL, mmdb:cn, Proxy")) } log.debug(conftmp) let packetTunnelMessage = PacketTunnelMessage(configData: Data(conftmp.utf8), serverIP: self.serverip,appGroup: bundleAppGroup) VPNHelper.shared.open(with: packetTunnelMessage, completion: { (error) in completion?(error) }) } func closeService(completion: (() -> Void)?) { VPNHelper.shared.close { self.serviceOpen = false completion?() } } func valueFromPlist(value: Int, file: String) -> String? { if let plistpath = Bundle.main.path(forResource: file, ofType: "entitlements") { if let entries = NSArray(contentsOfFile: plistpath) as Array? { // var entry = Dictionary() for entry in entries { if let id = entry.object(forKey:"id") as? Int { if id == value { if let name = entry.object(forKey:"name") as? String { return name } } } } } } return nil } }