package httpreverse import ( "b612.me/apps/b612/httpreverse/rp" "b612.me/starlog" "b612.me/staros/sysconf" "bufio" "errors" "io" "io/ioutil" "net" "net/http" "net/url" "os" "strings" "sync" ) type ReverseConfig struct { Name string Addr string ReverseURL map[string]*url.URL Port int UsingSSL bool Key string Cert string Host string SkipSSLVerify bool InHeader [][2]string OutHeader [][2]string Cookie [][3]string //[3]string should contains path::key::value ReplaceList [][2]string ReplaceOnce bool proxy map[string]*rp.ReverseProxy IPFilterMode int //0=off 1=useremote 2=add 3=filter FilterXForward bool FilterRemoteAddr bool FilterMustKey string FilterSetKey string FilterFile string httpmux http.ServeMux httpserver http.Server CIDR []*net.IPNet basicAuthUser string basicAuthPwd string protectAuthPage []string blackip map[string]int whiteip map[string]int warningpage string warnpagedata []byte } type HttpReverseServer struct { Config []*ReverseConfig } func Parse(path string) (HttpReverseServer, error) { var res HttpReverseServer ini := sysconf.NewIni() err := ini.ParseFromFile(path) if err != nil { return res, err } for _, v := range ini.Data { var ins = ReverseConfig{ Name: v.Name, Host: v.Get("host"), Addr: v.Get("addr"), Port: v.Int("port"), UsingSSL: v.Bool("enablessl"), Key: v.Get("key"), Cert: v.Get("cert"), ReplaceOnce: v.Bool("replaceonce"), IPFilterMode: v.Int("ipfiltermode"), FilterXForward: v.Bool("filterxforward"), FilterRemoteAddr: v.Bool("filterremoteaddr"), FilterMustKey: v.Get("filtermustkey"), FilterSetKey: v.Get("filtersetkey"), FilterFile: v.Get("filterfile"), basicAuthUser: v.Get("authuser"), basicAuthPwd: v.Get("authpasswd"), warningpage: v.Get("warnpage"), } if ins.IPFilterMode == 3 && ins.FilterFile != "" { starlog.Infoln("IP Filter Mode 3, Load IP Filter File", ins.FilterFile) f, err := os.Open(ins.FilterFile) if err != nil { return res, err } buf := bufio.NewReader(f) count := 0 for { line, err := buf.ReadString('\n') if err != nil { if err == io.EOF { f.Close() break } f.Close() return res, err } line = strings.TrimSpace(line) if !strings.Contains(line, "/") { line += "/32" //todo:区分IPV6 } _, cidr, err := net.ParseCIDR(line) if err != nil { return res, err } ins.CIDR = append(ins.CIDR, cidr) count++ } starlog.Infoln("Load", count, "CIDR") } if ins.warningpage != "" { data, err := ioutil.ReadFile(ins.warningpage) if err != nil { return res, err } ins.warnpagedata = data } ins.proxy = make(map[string]*rp.ReverseProxy) ins.ReverseURL = make(map[string]*url.URL) for _, reverse := range v.GetAll("reverse") { kv := strings.SplitN(reverse, "::", 2) if len(kv) != 2 { return res, errors.New("reverse settings not correct:" + reverse) } ins.ReverseURL[strings.TrimSpace(kv[0])], err = url.Parse(strings.TrimSpace(kv[1])) if err != nil { return res, err } } for _, header := range v.GetAll("inheader") { kv := strings.SplitN(header, "::", 2) if len(kv) != 2 { return res, errors.New("header settings not correct:" + header) } ins.InHeader = append(ins.InHeader, [2]string{strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1])}) } for _, authpage := range v.GetAll("authpage") { ins.protectAuthPage = append(ins.protectAuthPage, authpage) } ins.blackip = make(map[string]int) for _, blackip := range v.GetAll("blackip") { ip, cidr, err := IPCIDR(blackip) if err != nil { return res, err } ins.blackip[ip] = cidr } ins.whiteip = make(map[string]int) for _, whiteip := range v.GetAll("whiteip") { ip, cidr, err := IPCIDR(whiteip) if err != nil { return res, err } ins.whiteip[ip] = cidr } for _, header := range v.GetAll("outheader") { kv := strings.SplitN(header, "::", 2) if len(kv) != 2 { return res, errors.New("header settings not correct:" + header) } ins.OutHeader = append(ins.OutHeader, [2]string{strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1])}) } for _, cookie := range v.GetAll("cookie") { kv := strings.SplitN(cookie, "::", 3) if len(kv) != 3 { return res, errors.New("cookie settings not correct:" + cookie) } ins.Cookie = append(ins.Cookie, [3]string{strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1]), strings.TrimSpace(kv[2])}) } for _, replace := range v.GetAll("replace") { kv := strings.SplitN(replace, "::", 2) if len(kv) != 2 { return res, errors.New("replace settings not correct:" + replace) } ins.ReplaceList = append(ins.ReplaceList, [2]string{strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1])}) } res.Config = append(res.Config, &ins) } return res, nil } func (h *HttpReverseServer) Run() error { var wg sync.WaitGroup var mu sync.Mutex var haveErr string for _, v := range h.Config { wg.Add(1) go func(v *ReverseConfig) { defer wg.Done() err := v.Run() if err != nil { mu.Lock() haveErr += err.Error() + "\n" mu.Unlock() } }(v) } wg.Wait() if haveErr != "" { return errors.New(haveErr) } return nil } func (h *HttpReverseServer) Close() error { var haveErr string for _, v := range h.Config { err := v.Close() if err != nil { haveErr += err.Error() + "\n" } } if haveErr != "" { return errors.New(haveErr) } return nil }