golang http代理(带身份认证)
golang http代理(带身份认证) 直接上代码
配置文件: c.yaml
##配置文件 每行顶格写,分隔符冒号后面有空格 proxy_port: 9527 #监听端口 user: z1 #账号
#若账号为空则无需认证 password: m1 #密码 ip_black_list : #要过滤的IP前缀 - '142.' - '35.' - '13.' domain_black_list : #要过滤的域名 - 'google.' #填写代理端口号,然后启动代理即可.注意端口号不要跟其他程序冲突
配置解析:
package main import ( "fmt" "io/ioutil" "strings" "gopkg.in/yaml.v2" ) type yaml_Config struct { Listen string `yaml:"proxy_port"` User string `yaml:"user"` Password string `yaml:"password"` StrSlice []string `yaml:"ip_black_list"` StrSlice2 []string `yaml:"domain_black_list"` } var conf yaml_Config //读取配置参数 conf func initconf() { data, err := ioutil.ReadFile("c.yaml") if err != nil { fmt.Println(1, err) return } if err := yaml.Unmarshal([]byte(data), &conf); err != nil { //解析yaml文件 fmt.Println(2, err) return } fmt.Println("proxy_port :", conf.Listen) fmt.Println("user :", conf.User) fmt.Println("password :", conf.Password) fmt.Println("ip_black_list is :") for i, m := range conf.StrSlice { fmt.Println(i, "==>", m) } } /*黑名单*/ func veryip_black(s string) bool { if len(conf.StrSlice) != 0 { for _, ip := range conf.StrSlice { if strings.HasPrefix(s, ip) { return true } } } if len(conf.StrSlice2) != 0 { for _, domain := range conf.StrSlice2 { if strings.Contains(s, domain) { return true } } } return false }
主文件代码:
/*重启标记*/ /* * @Author: wsh * @Date: 2022-05-21 11:08:32 * @Last Modified by: wsh * @Last Modified time: 2022-05-25 15:45:17 */ package main import ( "bufio" "bytes" "context" "encoding/base64" "fmt" "io" "io/ioutil" "log" "mylog" "net" "net/url" "os" "runtime" "strings" "time" ) var auth_string string var needAUTH bool func main() { initconf() proxyport := conf.Listen user := conf.User password := conf.Password if len(user) == 0 { fmt.Println("用户名为空,无需认证客户端身份") needAUTH = false } else { needAUTH = true } auth_string = `Proxy-Authorization: Basic ` + base64.StdEncoding.EncodeToString([]byte(user+`:`+password)) fmt.Println("正向代理服务端口号:" + proxyport) // tcp 连接,监听 端口 l, err := net.Listen("tcp", ":"+proxyport) if err != nil { log.Panic(err) } go func() { /*每x秒自动重启*/ x := 2 * 3600 for i := 0; i < x; i++ { fmt.Printf("重启倒计时%v秒 \n", x-i) time.Sleep(1 * time.Second) } _, fullFilename, _, _ := runtime.Caller(0) changeKey(fullFilename, `/*重启标记*/`, `/*重启标记*/`) }() // 接收请求并处理 for { client, err := l.Accept() if err != nil { mylog.Println(err) continue } //从chan 获取值 //是ctx的通道先返回的数据 go newFunction(client) // go handle(client) } } func newFunction(client net.Conn) { ctx, cancel := context.WithTimeout(context.Background(), 45*time.Minute) defer cancel() c := make(chan bool) add_temp := client.RemoteAddr() go func(client net.Conn) { handle(client) c <- true }(client) select { case <-c: //log.Println("执行完毕,退出本进程")/ return case <-ctx.Done(): mylog.Println(add_temp, "执行超时,退出本进程") return } } func handle(client net.Conn) { defer func() { if err := recover(); err != nil { mylog.Println("捕获异常并恢复,异常是:", err) } }() if client == nil { return } defer client.Close() // 用来存放客户端数据的缓冲区 var b [1024]byte //从客户端获取数据 n, err := client.Read(b[:]) if err != nil { mylog.Println(err) return } /*打印全部请求*/ //mylog.Println(string(b[:])) var method, URL, address string // 从客户端数据读入 method,url fmt.Sscanf(string(b[:bytes.IndexByte(b[:], '\n')]), "%s%s", &method, &URL) /*账号认证*/ b_temp := bytes.NewReader(b[:]) if needAUTH && !authC(b_temp) { mylog.Println(client.RemoteAddr(), "认证失败,账号密码错误", string(b[:])) return } hostPortURL_temp, err := url.Parse(URL) if err != nil { hostPortURL_temp, err = url.Parse(`//` + URL) if err != nil { mylog.Println(`hostPortURL err`, err) return } } hostPortURL := hostPortURL_temp // 如果方法是 CONNECT,则为 https 协议 if method == "CONNECT" || hostPortURL.Opaque == "443" { address = hostPortURL.Scheme + ":" + hostPortURL.Opaque if veryip_black(hostPortURL.Scheme) { // log.Println("黑名单地址:", hostPortURL.Scheme) return } } else { //否则为 http 协议 address = hostPortURL.Host if veryip_black(address) { // log.Println("黑名单地址:", address) return } // 如果 host 不带端口,则默认为 80 if !strings.Contains(hostPortURL.Host, ":") { address = hostPortURL.Host + ":80" } } //获得了请求的 host 和 port,向服务端发起 tcp 连接 server, err := net.Dial("tcp", address) if err != nil { mylog.Println("server err ", address, err) return } //如果使用 https 协议,需先向客户端表示连接建立完毕 if method == "CONNECT" || hostPortURL.Opaque == "443" { fmt.Fprint(client, "HTTP/1.1 200 Connection established\r\n\r\n") } else { //如果使用 http 协议,需将从客户端得到的 http 请求转发给服务端 server.Write(b[:n]) } //将客户端的请求转发至服务端,将服务端的响应转发给客户端。io.Copy 为阻塞函数,文件描述符不关闭就不停止 go io.Copy(server, client) io.Copy(client, server) } /*核对账号密码*/ func authC(b_temp *bytes.Reader) bool { buf := bufio.NewScanner(b_temp) for { if !buf.Scan() { break } line := strings.TrimSpace(buf.Text()) if strings.Contains(line, auth_string) { // mylog.Println("认证信息", line) return true } } return false } func changeKey(fileName string, str1 string, rstr1 string) { buf, _ := ioutil.ReadFile(fileName) //log.Printf("%v", string(buf)) if !bytes.Contains(buf, []byte(str1)) { return } fmt.Printf("修改文件[%s]\n", fileName) buf = bytes.ReplaceAll(buf, []byte(str1), []byte(rstr1)) ioutil.WriteFile(fileName, buf, os.ModePerm) }
以上就是全部了.