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)
}

  

 

 

以上就是全部了.

 

posted @ 2022-05-24 10:45  wsh3166Sir  阅读(894)  评论(0编辑  收藏  举报