add new file

This commit is contained in:
he liu
2022-01-23 17:30:38 +08:00
parent 05b2e55f39
commit c482967f8c
125 changed files with 9688 additions and 0 deletions

71
core/handler/default.go Normal file
View File

@@ -0,0 +1,71 @@
package handler
import (
"ehang.io/nps/lib/enet"
)
var (
_ Handler = (*HttpHandler)(nil)
_ Handler = (*HttpsHandler)(nil)
_ Handler = (*RdpHandler)(nil)
_ Handler = (*RedisHandler)(nil)
_ Handler = (*Socks5Handler)(nil)
_ Handler = (*TransparentHandler)(nil)
_ Handler = (*DefaultHandler)(nil)
_ Handler = (*DnsHandler)(nil)
_ Handler = (*P2PHandler)(nil)
_ Handler = (*QUICHandler)(nil)
_ Handler = (*DefaultHandler)(nil)
_ Handler = (*Socks5UdpHandler)(nil)
)
type RuleRun interface {
RunConn(enet.Conn) (bool, error)
RunPacketConn(enet.PacketConn) (bool, error)
}
type DefaultHandler struct {
ruleList []RuleRun
}
func NewBaseTcpHandler() *DefaultHandler {
return &DefaultHandler{ruleList: make([]RuleRun, 0)}
}
func (b *DefaultHandler) GetName() string {
return "default"
}
func (b *DefaultHandler) GetZhName() string {
return "默认"
}
func (b *DefaultHandler) HandleConn(_ []byte, c enet.Conn) (bool, error) {
return b.processConn(c)
}
func (b *DefaultHandler) AddRule(r RuleRun) {
b.ruleList = append(b.ruleList, r)
}
func (b *DefaultHandler) HandlePacketConn(_ enet.PacketConn) (bool, error) {
return false, nil
}
func (b *DefaultHandler) processConn(c enet.Conn) (bool, error) {
for _, r := range b.ruleList {
if ok, err := r.RunConn(c); err != nil || ok {
return ok, err
}
}
return false, nil
}
func (b *DefaultHandler) processPacketConn(pc enet.PacketConn) (bool, error) {
for _, r := range b.ruleList {
if ok, err := r.RunPacketConn(pc); err != nil || ok {
return ok, err
}
}
return false, nil
}

35
core/handler/dns.go Normal file
View File

@@ -0,0 +1,35 @@
package handler
import (
"ehang.io/nps/lib/enet"
"ehang.io/nps/lib/logger"
"github.com/miekg/dns"
"go.uber.org/zap"
)
type DnsHandler struct {
DefaultHandler
}
func (dh *DnsHandler) GetName() string {
return "dns"
}
func (dh *DnsHandler) GetZhName() string {
return "dns协议"
}
func (dh *DnsHandler) HandlePacketConn(pc enet.PacketConn) (bool, error) {
b, _, err := pc.FirstPacket()
if err != nil {
logger.Warn("firstPacket error", zap.Error(err))
return false, nil
}
m := new(dns.Msg)
err = m.Unpack(b)
if err != nil {
logger.Debug("parse dns request error", zap.Error(err))
return false, nil
}
return dh.processPacketConn(pc)
}

46
core/handler/dns_test.go Normal file
View File

@@ -0,0 +1,46 @@
package handler
import (
"ehang.io/nps/lib/enet"
"github.com/miekg/dns"
"github.com/stretchr/testify/assert"
"net"
"testing"
)
type testRule struct {
run bool
}
func (t *testRule) RunConn(c enet.Conn) (bool, error) {
t.run = true
return true, nil
}
func (t *testRule) RunPacketConn(_ enet.PacketConn) (bool, error) {
t.run = true
return true, nil
}
func TestHandleDnsPacket(t *testing.T) {
lPacketConn, err := net.ListenPacket("udp", "127.0.0.1:0")
assert.NoError(t, err)
h := DnsHandler{}
rule := &testRule{}
h.AddRule(rule)
m := new(dns.Msg)
m.SetQuestion(dns.Fqdn("www.google.com"), dns.TypeA)
m.RecursionDesired = true
b, err := m.Pack()
assert.NoError(t, err)
pc := enet.NewReaderPacketConn(nil, b, lPacketConn.LocalAddr())
assert.NoError(t, pc.SendPacket(b, nil))
res, err := h.HandlePacketConn(pc)
assert.NoError(t, err)
assert.Equal(t, true, res)
assert.Equal(t, true, rule.run)
}

11
core/handler/handler.go Normal file
View File

@@ -0,0 +1,11 @@
package handler
import "ehang.io/nps/lib/enet"
type Handler interface {
GetName() string
GetZhName() string
AddRule(RuleRun)
HandleConn([]byte, enet.Conn) (bool, error)
HandlePacketConn(enet.PacketConn) (bool, error)
}

30
core/handler/http.go Normal file
View File

@@ -0,0 +1,30 @@
package handler
import (
"ehang.io/nps/lib/enet"
"net/http"
)
type HttpHandler struct {
DefaultHandler
}
func NewHttpHandler() *HttpHandler {
return &HttpHandler{}
}
func (h *HttpHandler) GetName() string {
return "http"
}
func (h *HttpHandler) GetZhName() string {
return "http协议"
}
func (h *HttpHandler) HandleConn(b []byte, c enet.Conn) (bool, error) {
switch string(b[:3]) {
case http.MethodGet[:3], http.MethodHead[:3], http.MethodPost[:3], http.MethodPut[:3], http.MethodPatch[:3], http.MethodDelete[:3], http.MethodConnect[:3], http.MethodOptions[:3], http.MethodTrace[:3]:
return h.processConn(c)
}
return false, nil
}

27
core/handler/http_test.go Normal file
View File

@@ -0,0 +1,27 @@
package handler
import (
"github.com/stretchr/testify/assert"
"net/http"
"net/http/httputil"
"testing"
)
func TestHandleHttpConn(t *testing.T) {
h := HttpHandler{}
rule := &testRule{}
h.AddRule(rule)
r, err := http.NewRequest("GET", "/", nil)
assert.NoError(t, err)
b, err := httputil.DumpRequest(r, false)
assert.NoError(t, err)
res, err := h.HandleConn(b, nil)
assert.NoError(t, err)
assert.Equal(t, true, res)
assert.Equal(t, true, rule.run)
}

33
core/handler/https.go Normal file
View File

@@ -0,0 +1,33 @@
package handler
import (
"ehang.io/nps/lib/enet"
)
const (
recordTypeHandshake uint8 = 22
typeClientHello uint8 = 1
)
type HttpsHandler struct {
DefaultHandler
}
func NewHttpsHandler() *HttpsHandler {
return &HttpsHandler{}
}
func (h *HttpsHandler) GetName() string {
return "https"
}
func (h *HttpsHandler) GetZhName() string {
return "https协议"
}
func (h *HttpsHandler) HandleConn(b []byte, c enet.Conn) (bool, error) {
if b[0] == recordTypeHandshake{
return h.processConn(c)
}
return false, nil
}

View File

@@ -0,0 +1,39 @@
package handler
import (
"crypto/tls"
"ehang.io/nps/lib/enet"
"github.com/stretchr/testify/assert"
"net"
"testing"
)
func TestHandleHttpsConn(t *testing.T) {
h := HttpsHandler{}
rule := &testRule{}
h.AddRule(rule)
finish := make(chan struct{}, 0)
ln, err := net.Listen("tcp", "127.0.0.1:0")
assert.NoError(t, err)
go func() {
conn, err := ln.Accept()
assert.NoError(t, err)
buf := make([]byte, 1024)
n, err := conn.Read(buf)
assert.NoError(t, err)
res, err := h.HandleConn(buf[:n], enet.NewReaderConn(conn))
assert.NoError(t, err)
assert.Equal(t, true, res)
assert.Equal(t, true, rule.run)
finish <- struct{}{}
}()
go func() {
_, err = tls.Dial("tcp", ln.Addr().String(), &tls.Config{
InsecureSkipVerify: true,
})
assert.NoError(t, err)
}()
<-finish
}

32
core/handler/p2p.go Normal file
View File

@@ -0,0 +1,32 @@
package handler
import (
"bytes"
"ehang.io/nps/lib/enet"
"ehang.io/nps/lib/logger"
"go.uber.org/zap"
)
type P2PHandler struct {
DefaultHandler
}
func (ph *P2PHandler) GetName() string {
return "p2p"
}
func (ph *P2PHandler) GetZhName() string {
return "点对点协议"
}
func (ph *P2PHandler) HandlePacketConn(pc enet.PacketConn) (bool, error) {
b, _, err := pc.FirstPacket()
if err != nil {
logger.Warn("firstPacket error", zap.Error(err))
return false, nil
}
if bytes.HasPrefix(b, []byte("p2p")) {
return ph.processPacketConn(pc)
}
return false, nil
}

26
core/handler/p2p_test.go Normal file
View File

@@ -0,0 +1,26 @@
package handler
import (
"ehang.io/nps/lib/enet"
"github.com/stretchr/testify/assert"
"net"
"testing"
)
func TestHandleP2PPacket(t *testing.T) {
h := P2PHandler{}
rule := &testRule{}
h.AddRule(rule)
addr, err := net.ResolveUDPAddr("udp", "127.0.0.1:8080")
assert.NoError(t, err)
pc := enet.NewReaderPacketConn(nil, []byte("p2p xxxx"), addr)
assert.NoError(t, pc.SendPacket([]byte("p2p xxxx"), nil))
res, err := h.HandlePacketConn(pc)
assert.NoError(t, err)
assert.Equal(t, true, res)
assert.Equal(t, true, rule.run)
}

32
core/handler/quic.go Normal file
View File

@@ -0,0 +1,32 @@
package handler
import (
"bytes"
"ehang.io/nps/lib/enet"
"ehang.io/nps/lib/logger"
"go.uber.org/zap"
)
type QUICHandler struct {
DefaultHandler
}
func (qh *QUICHandler) GetName() string {
return "quic"
}
func (qh *QUICHandler) GetZhName() string {
return "quic协议"
}
func (qh *QUICHandler) HandlePacketConn(pc enet.PacketConn) (bool, error) {
b, _, err := pc.FirstPacket()
if err != nil {
logger.Warn("firstPacket error", zap.Error(err))
return false, nil
}
if len(b) >= 5 && bytes.HasPrefix(b[1:5], []byte{0, 0, 0, 1}) {
return qh.processPacketConn(pc)
}
return false, nil
}

35
core/handler/quic_test.go Normal file
View File

@@ -0,0 +1,35 @@
package handler
import (
"crypto/tls"
"ehang.io/nps/lib/enet"
"github.com/lucas-clemente/quic-go"
"github.com/stretchr/testify/assert"
"net"
"testing"
)
func TestHandleQUICPacket(t *testing.T) {
h := QUICHandler{}
rule := &testRule{}
h.AddRule(rule)
finish := make(chan struct{}, 0)
packetConn, err := net.ListenPacket("udp", "127.0.0.1:0")
assert.NoError(t, err)
go func() {
b := make([]byte, 1500)
n, addr, err := packetConn.ReadFrom(b)
assert.NoError(t, err)
pc := enet.NewReaderPacketConn(nil, b[:n], packetConn.LocalAddr())
assert.NoError(t, pc.SendPacket(b[:n], addr))
res, err := h.HandlePacketConn(pc)
assert.NoError(t, err)
assert.Equal(t, true, res)
assert.Equal(t, true, rule.run)
finish <- struct{}{}
}()
go quic.DialAddr(packetConn.LocalAddr().String(), &tls.Config{}, nil)
<-finish
}

24
core/handler/rdp.go Normal file
View File

@@ -0,0 +1,24 @@
package handler
import (
"ehang.io/nps/lib/enet"
)
type RdpHandler struct {
DefaultHandler
}
func (rh *RdpHandler) GetName() string {
return "rdp"
}
func (rh *RdpHandler) GetZhName() string {
return "rdp协议"
}
func (rh *RdpHandler) HandleConn(b []byte, c enet.Conn) (bool, error) {
if b[0] == 3 && b[1] == 0 {
return rh.processConn(c)
}
return false, nil
}

37
core/handler/rdp_test.go Normal file
View File

@@ -0,0 +1,37 @@
package handler
import (
"ehang.io/nps/lib/enet"
"github.com/icodeface/grdp"
"github.com/icodeface/grdp/glog"
"github.com/stretchr/testify/assert"
"net"
"testing"
)
func TestHandleRdpConn(t *testing.T) {
h := RdpHandler{}
rule := &testRule{}
h.AddRule(rule)
finish := make(chan struct{}, 0)
ln, err := net.Listen("tcp", "127.0.0.1:0")
assert.NoError(t, err)
go func() {
conn, err := ln.Accept()
assert.NoError(t, err)
buf := make([]byte, 1024)
n, err := conn.Read(buf)
assert.NoError(t, err)
res, err := h.HandleConn(buf[:n], enet.NewReaderConn(conn))
assert.NoError(t, err)
assert.Equal(t, true, res)
assert.Equal(t, true, rule.run)
finish <- struct{}{}
}()
go func() {
grdp.NewClient(ln.Addr().String(), glog.DEBUG).Login("Administrator", "123456")
}()
<-finish
}

22
core/handler/redis.go Normal file
View File

@@ -0,0 +1,22 @@
package handler
import "ehang.io/nps/lib/enet"
type RedisHandler struct {
DefaultHandler
}
func (rds *RedisHandler) GetName() string {
return "redis"
}
func (rds *RedisHandler) GetZhName() string {
return "redis协议"
}
func (rds *RedisHandler) HandleConn(b []byte, c enet.Conn) (bool, error) {
if b[0] == 42 && b[1] == 49 && b[2] == 13 {
return rds.processConn(c)
}
return false, nil
}

View File

@@ -0,0 +1,40 @@
package handler
import (
"context"
"ehang.io/nps/lib/enet"
"github.com/go-redis/redis/v8"
"github.com/stretchr/testify/assert"
"net"
"testing"
)
func TestHandleRedisConn(t *testing.T) {
h := RedisHandler{}
rule := &testRule{}
h.AddRule(rule)
finish := make(chan struct{}, 0)
ln, err := net.Listen("tcp", "127.0.0.1:0")
assert.NoError(t, err)
go func() {
conn, err := ln.Accept()
assert.NoError(t, err)
buf := make([]byte, 1024)
n, err := conn.Read(buf)
assert.NoError(t, err)
res, err := h.HandleConn(buf[:n], enet.NewReaderConn(conn))
assert.NoError(t, err)
assert.Equal(t, true, res)
assert.Equal(t, true, rule.run)
finish <- struct{}{}
}()
go func() {
rdb := redis.NewClient(&redis.Options{
Addr: ln.Addr().String(),
})
rdb.Ping(context.Background())
}()
<-finish
}

22
core/handler/socks5.go Normal file
View File

@@ -0,0 +1,22 @@
package handler
import "ehang.io/nps/lib/enet"
type Socks5Handler struct {
DefaultHandler
}
func (sh *Socks5Handler) GetName() string {
return "socks5"
}
func (sh *Socks5Handler) GetZhName() string {
return "socks5协议"
}
func (sh *Socks5Handler) HandleConn(b []byte, c enet.Conn) (bool, error) {
if b[0] == 5 {
return sh.processConn(c)
}
return false, nil
}

View File

@@ -0,0 +1,47 @@
package handler
import (
"crypto/tls"
"ehang.io/nps/lib/enet"
"fmt"
"github.com/stretchr/testify/assert"
"net"
"net/http"
"net/url"
"testing"
)
func TestHandleSocks5Conn(t *testing.T) {
h := Socks5Handler{}
rule := &testRule{}
h.AddRule(rule)
finish := make(chan struct{}, 0)
ln, err := net.Listen("tcp", "127.0.0.1:0")
assert.NoError(t, err)
go func() {
conn, err := ln.Accept()
assert.NoError(t, err)
buf := make([]byte, 1024)
n, err := conn.Read(buf)
assert.NoError(t, err)
res, err := h.HandleConn(buf[:n], enet.NewReaderConn(conn))
assert.NoError(t, err)
assert.Equal(t, true, res)
assert.Equal(t, true, rule.run)
finish <- struct{}{}
}()
go func() {
transport := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
Proxy: func(_ *http.Request) (*url.URL, error) {
return url.Parse(fmt.Sprintf("socks5://%s", ln.Addr().String()))
},
}
client := &http.Client{Transport: transport}
_, _ = client.Get("https://google.com/")
}()
<-finish
}

View File

@@ -0,0 +1,26 @@
package handler
import "ehang.io/nps/lib/enet"
type Socks5UdpHandler struct {
DefaultHandler
}
func (sh *Socks5UdpHandler) GetName() string {
return "socks5_udp"
}
func (sh *Socks5UdpHandler) GetZhName() string {
return "socks5 udp协议"
}
func (sh *Socks5UdpHandler) HandlePacketConn(pc enet.PacketConn) (bool, error) {
b, _, err := pc.FirstPacket()
if err != nil {
return true, err
}
if b[0] == 0 {
return sh.processPacketConn(pc)
}
return false, nil
}

View File

@@ -0,0 +1,44 @@
package handler
import (
"ehang.io/nps/lib/common"
"ehang.io/nps/lib/enet"
"github.com/stretchr/testify/assert"
"net"
"testing"
)
func TestSocks5Handle(t *testing.T) {
h := Socks5UdpHandler{}
rule := &testRule{}
h.AddRule(rule)
finish := make(chan struct{}, 0)
pc, err := net.ListenPacket("udp", "127.0.0.1:0")
assert.NoError(t, err)
go func() {
buf := make([]byte, 1024)
n, addr, err := pc.ReadFrom(buf)
assert.NoError(t, err)
rPc := enet.NewReaderPacketConn(nil, buf[:n], addr)
res, err := h.HandlePacketConn(rPc)
assert.NoError(t, err)
assert.Equal(t, true, res)
assert.Equal(t, true, rule.run)
finish <- struct{}{}
}()
data := []byte("test")
go func() {
cPc, err := net.ListenPacket("udp", "127.0.0.1:0")
assert.NoError(t, err)
pAddr, err := common.ParseAddr("8.8.8.8:53")
assert.NoError(t, err)
b := append([]byte{0, 0, 0}, pAddr...)
b = append(b, data...)
_, err = cPc.WriteTo(b, pc.LocalAddr())
assert.NoError(t, err)
}()
<-finish
}

View File

@@ -0,0 +1,21 @@
package handler
import (
"ehang.io/nps/lib/enet"
)
type TransparentHandler struct {
DefaultHandler
}
func (ts *TransparentHandler) GetName() string {
return "transparent"
}
func (ts *TransparentHandler) GetZhName() string {
return "linux透明代理协议"
}
func (ts *TransparentHandler) HandleConn(b []byte, c enet.Conn) (bool, error) {
return ts.processConn(c)
}