func (p *Proxy) Command(commands string, f *profile.Profile, v *life.Life) { commandLines := strings.Split(commands, "\n") for _, line := range commandLines { line = strings.TrimSpace(line) if len(line) <= 0 || line[0] == '#' { continue } c, rest := cmd.TakeFirstArg(line) switch c { case "restart": if v != nil { v.Restart() } case "clear": f.Clear() case "domain": f.CommandDomain(rest) case "url": f.CommandUrl(rest) case "host": c, rest = cmd.TakeFirstArg(rest) if ip, domain, ok := parseIPDomain(c, rest); ok { f.CommandDomain(domain + " " + ip) } default: if ip, domain, ok := parseIPDomain(c, rest); ok { f.CommandDomain(domain + " " + ip) } } } }
func takeDuration(content string) (bool, float32, string, bool) { rand := false d, p := cmd.TakeFirstArg(content) if d == "rand" { rand = true d, p = cmd.TakeFirstArg(p) } duration := parseDuration(d) return rand, duration, p, duration >= 0 }
func commandDomainMode(p *Profile, mode, content string) { c, rest := cmd.TakeFirstArg(content) if c == "" { return } act := DomainActNone if mode != "redirect" && rest != "" { return } ip := "" if mode == "block" { act = DomainActBlock } else if mode == "redirect" { if rest != "" { addr := net.ParseIP(rest) if addr == nil { return } else { ip = addr.String() } } act = DomainActRedirect } if c == "all" { p.SetAllDomainAction(DomainAct(act), ip) } else { p.SetDomainAction(c, DomainAct(act), ip) } }
func parseUrlProxyAction(c, rest string) (*UrlProxyAction, string, bool) { var act UrlAct = UrlActNone value := "" if c == "proxy" { act = UrlActNone } else if c == "cache" { act = UrlActCache } else { switch c { case "status": act = UrlActStatus case "map": act = UrlActMap case "redirect": act = UrlActRedirect case "rewrite": act = UrlActRewritten case "restore": act = UrlActRestore case "tcpwrite": act = UrlActTcpWritten default: return nil, "", false } value, rest = cmd.TakeFirstArg(rest) } return &UrlProxyAction{act, value}, rest, true }
func commandDomainMode(p *Profile, mode, content string) { c, rest := cmd.TakeFirstArg(content) if c == "" { return } ip := "" if rest != "" { addr := net.ParseIP(rest) if addr == nil { return } else { ip = addr.String() } } act := new(DomainAct) if mode == "" { act = nil } else if mode == "default" { *act = DomainActNone } else if mode == "block" { *act = DomainActBlock } else if mode == "proxy" { *act = DomainActProxy } else if mode == "null" { *act = DomainActNull } if c == "all" { p.SetAllDomainAction(act, ip) } else { p.SetDomainAction(c, act, ip) } }
func commandProxyMode(p *Profile, mode, args string) { var act UrlAct = UrlActNone if mode == "cache" { act = UrlActCache } else if mode == "drop" { act = UrlActStatus } dropResponseCode := 0 if act == UrlActStatus { r, rest := cmd.TakeFirstArg(args) responseCode, err := strconv.Atoi(r) if err != nil { return } else { dropResponseCode = responseCode args = rest } } pattern := restToPattern(args) if pattern == "all" { p.SetAllUrlAction(act, dropResponseCode) } else if len(pattern) > 0 { p.SetUrlAction(pattern, act, dropResponseCode) } }
func delayTimeAndPattern(content string) (float32, string, bool) { d, p := cmd.TakeFirstArg(content) duration := parseDuration(d) pattern := restToPattern(p) ok := duration >= 0 && len(pattern) > 0 return duration, pattern, ok }
func takeBodyDuration(content string) (bool, bool, float32, string, bool) { body := false rand := false d, p := cmd.TakeFirstArg(content) for { if d == "rand" { rand = true } else if d == "body" { body = true } else { break } d, p = cmd.TakeFirstArg(p) } duration := parseDuration(d) return body, rand, duration, p, duration >= 0 }
func (p *Profile) CommandDomain(content string) { c, rest := cmd.TakeFirstArg(content) switch c { case "default", "block", "proxy", "null": commandDomainMode(p, c, rest) case "delete": commandDomainDelete(p, rest) default: commandDomainMode(p, "", content) } }
func parseIPDomain(c, rest string) (string, string, bool) { ip := net.ParseIP(c) if ip != nil { d, r := cmd.TakeFirstArg(rest) if len(d) > 0 && len(r) == 0 { return c, d, true } } return "", "", false }
func (p *Profile) CommandDelay(content string) { c, rest := cmd.TakeFirstArg(content) switch c { case "default": commandDelayMode(p, c, rest) case "drop": commandDelayMode(p, c, rest) default: commandDelayMode(p, "default", content) } }
func commandDomainDelete(p *Profile, content string) { c, rest := cmd.TakeFirstArg(content) if c == "" || rest != "" { return } if c == "all" { p.DeleteAllDomain() } else { p.DeleteDomain(c) } }
func restToPattern(content string) string { url, rest := cmd.TakeFirstArg(content) if len(rest) > 0 { return "" } if url == "all" { return url } return UrlToPattern(url) }
func (p *Profile) CommandProxy(content string) { c, rest := cmd.TakeFirstArg(content) switch c { case "default": commandProxyMode(p, c, rest) case "cache": commandProxyMode(p, c, rest) case "status": commandProxyMode(p, c, rest) default: commandProxyMode(p, "default", content) } }
func parseSpeedAction(c, rest string) (*SpeedAction, string, bool) { var act SpeedActType = SpeedActConstant var speed float32 = 0 value := "" value, rest = cmd.TakeFirstArg(rest) s, ok := parseSpeed(value) if ok { speed = s } else { return nil, rest, false } return &SpeedAction{act, speed}, rest, true }
func (p *Profile) CommandUrl(content string) { c, rest := "", content ok := false var delayAction *DelayAction var proxyAction *UrlProxyAction for { c, rest = cmd.TakeFirstArg(rest) switch c { case "delay": fallthrough case "drop": fallthrough case "timeout": delayAction, rest, ok = parseDelayAction(c, rest) if !ok { return } case "cache": fallthrough case "status": fallthrough case "map": fallthrough case "redirect": fallthrough case "rewrite": fallthrough case "restore": proxyAction, rest, ok = parseUrlProxyAction(c, rest) if !ok { return } case "delete": p.CommandDelete(rest) return default: if len(c) > 0 && len(rest) == 0 { commandUrl(p, delayAction, proxyAction, c) } return } } }
func (p *Profile) Command(command string) { commandLines := strings.Split(command, "\n") for _, line := range commandLines { line = strings.TrimSpace(line) if len(line) <= 0 || line[0] == '#' { continue } c, rest := cmd.TakeFirstArg(line) switch c { case "delay": p.CommandDelay(rest) case "proxy": p.CommandProxy(rest) case "delete": p.CommandDelete(rest) case "domain": p.CommandDomain(rest) case "url": p.CommandUrl(rest) default: } } }
func (p *Profile) CommandUrl(content string) { c, rest := "", content ok := false var delayAction *DelayAction var bodyDelayAction *DelayAction var proxyAction *UrlProxyAction var speedAction *SpeedAction settings := make(map[string]string) set := false for { c, rest = cmd.TakeFirstArg(rest) switch c { case "delay": fallthrough case "drop": fallthrough case "timeout": action, body, r, ok := parseDelayAction(c, rest) if !ok { return } rest = r if body { bodyDelayAction = action } else { delayAction = action } case "proxy": fallthrough case "cache": fallthrough case "status": fallthrough case "map": fallthrough case "redirect": fallthrough case "rewrite": fallthrough case "restore": fallthrough case "tcpwrite": proxyAction, rest, ok = parseUrlProxyAction(c, rest) if !ok { return } case "speed": speedAction, rest, ok = parseSpeedAction(c, rest) if !ok { return } case "delete": p.CommandDelete(rest) return case "set": set = true if delayAction == nil { delayAction = new(DelayAction) } if bodyDelayAction == nil { bodyDelayAction = new(DelayAction) } if proxyAction == nil { proxyAction = new(UrlProxyAction) } if speedAction == nil { speedAction = new(SpeedAction) } case "update": case "dont302": settings["dont302"] = "on" case "do302": settings["dont302"] = "off" case "disable304": settings["disable304"] = "yes" case "allow304": settings["disable304"] = "no" case "content-type": v := "default" v, rest = cmd.TakeFirstArg(rest) settings["content-type"] = v default: if len(c) > 0 && len(rest) == 0 { commandUrl(p, set, delayAction, bodyDelayAction, proxyAction, speedAction, settings, c) } return } } }
func main() { version() flag.Parse() p := proxy.NewProxy(VersionCode) ipProfiles := profile.NewIpProfiles() ipProfiles.BindProxyHostOperator(p.NewProxyHostOperator()) ipProfiles.SetDefaultCopyProfile("localhost") p.BindUrlOperator(ipProfiles.OperatorUrl()) p.BindProfileOperator(ipProfiles.OperatorProfile()) p.BindDomainOperator(ipProfiles.OperatorDomain()) if *nodns { p.DisableDNS() } else { go dnsproxy.DnsProxy(dnsproxy.NewPolicy(p.NewDomainOperator())) } var c cmd.Command c.OpenConsole() for { fmt.Print("\n$ ") command := c.Read() command, rest := cmd.TakeFirstArg(command) switch command { case "": case "exit": return case "usage": fallthrough case "help": usage() case "version": version() case "bench": if len(rest) == 0 { fmt.Println("usage: bench <url>") } else { url := "http://" if strings.HasPrefix(rest, url) { url = rest } else { url += rest } benchN(url) } case "bind": port, err := strconv.Atoi(rest) if err != nil { fmt.Println("usage: bind <port>\nport: in 1~65535") } else { fmt.Println("") bindNew := p.Bind(port) if bindNew { fmt.Println("port", port, "binds ok") } else { fmt.Println("port had already bound") } } case "delete": mod, rest := cmd.TakeFirstArg(rest) switch mod { case "profile": if ipProfiles.Delete(rest) { fmt.Println(`profile "` + rest + `" deleted`) } else { fmt.Println(`profile "` + rest + `" don't exist`) } default: usage() } default: usage() fmt.Println(`UNKNOWN command: "` + command + `" ` + rest) } } }