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)
}
以上就是全部了.
浙公网安备 33010602011771号