golang http代理(帶身份認證)
阿新 • • 發佈:2022-05-24
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-24 10:43:51 */ package main import ( "bufio" "bytes" "encoding/base64" "fmt" "io" "log" "mylog" "net" "net/url" "strings" ) var auth_string string func main() { initconf() proxyport := conf.Listen user := conf.User password := conf.Password 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) } // 接收請求並處理 for { client, err := l.Accept() if err != nil { log.Panic(err) } go handle(client) } } func handle(client net.Conn) { if client == nil { return } defer client.Close() // 用來存放客戶端資料的緩衝區 var b [4096]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 !authC(b_temp) { mylog.Println(client.RemoteAddr(), "認證失敗,賬號密碼錯誤") return } hostPortURL, err := url.Parse(URL) if err != nil { mylog.Println(`hostPortURL err`, err) return } // 如果方法是 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 }
以上就是全部了.