mirror of
https://github.com/fatedier/frp.git
synced 2025-06-17 17:18:21 +00:00
Compare commits
1 Commits
ced2fb69b7
...
f2a87c6653
Author | SHA1 | Date | |
---|---|---|---|
|
f2a87c6653 |
@ -2,15 +2,24 @@ version: 2
|
|||||||
jobs:
|
jobs:
|
||||||
go-version-latest:
|
go-version-latest:
|
||||||
docker:
|
docker:
|
||||||
- image: cimg/go:1.22-node
|
- image: cimg/go:1.22-node
|
||||||
resource_class: large
|
resource_class: large
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run: make
|
- run: make
|
||||||
- run: make alltest
|
- run: make alltest
|
||||||
|
go-version-last:
|
||||||
|
docker:
|
||||||
|
- image: cimg/go:1.21-node
|
||||||
|
resource_class: large
|
||||||
|
steps:
|
||||||
|
- checkout
|
||||||
|
- run: make
|
||||||
|
- run: make alltest
|
||||||
|
|
||||||
workflows:
|
workflows:
|
||||||
version: 2
|
version: 2
|
||||||
build_and_test:
|
build_and_test:
|
||||||
jobs:
|
jobs:
|
||||||
- go-version-latest
|
- go-version-latest
|
||||||
|
- go-version-last
|
||||||
|
2
go.mod
2
go.mod
@ -1,6 +1,6 @@
|
|||||||
module github.com/fatedier/frp
|
module github.com/fatedier/frp
|
||||||
|
|
||||||
go 1.22
|
go 1.21
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
|
||||||
|
@ -45,6 +45,15 @@ func NewBandwidthQuantity(s string) (BandwidthQuantity, error) {
|
|||||||
return q, nil
|
return q, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MustBandwidthQuantity(s string) BandwidthQuantity {
|
||||||
|
q := BandwidthQuantity{}
|
||||||
|
err := q.UnmarshalString(s)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
|
||||||
func (q *BandwidthQuantity) Equal(u *BandwidthQuantity) bool {
|
func (q *BandwidthQuantity) Equal(u *BandwidthQuantity) bool {
|
||||||
if q == nil && u == nil {
|
if q == nil && u == nil {
|
||||||
return true
|
return true
|
||||||
|
@ -42,3 +42,7 @@ func ReadMsgInto(c io.Reader, msg Message) (err error) {
|
|||||||
func WriteMsg(c io.Writer, msg interface{}) (err error) {
|
func WriteMsg(c io.Writer, msg interface{}) (err error) {
|
||||||
return msgCtl.WriteMsg(c, msg)
|
return msgCtl.WriteMsg(c, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Pack(msg interface{}) (data []byte, err error) {
|
||||||
|
return msgCtl.Pack(msg)
|
||||||
|
}
|
||||||
|
@ -17,7 +17,7 @@ package nathole
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand/v2"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"slices"
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -341,7 +341,7 @@ func sendSidMessage(
|
|||||||
TransactionID: transactionID,
|
TransactionID: transactionID,
|
||||||
Sid: sid,
|
Sid: sid,
|
||||||
Response: false,
|
Response: false,
|
||||||
Nonce: strings.Repeat("0", rand.IntN(20)),
|
Nonce: strings.Repeat("0", rand.Intn(20)),
|
||||||
}
|
}
|
||||||
buf, err := EncodeMessage(m, key)
|
buf, err := EncodeMessage(m, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -398,7 +398,7 @@ func sendSidMessageToRandomPorts(
|
|||||||
used := sets.New[int]()
|
used := sets.New[int]()
|
||||||
getUnusedPort := func() int {
|
getUnusedPort := func() int {
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
port := rand.IntN(65535-1024) + 1024
|
port := rand.Intn(65535-1024) + 1024
|
||||||
if !used.Has(port) {
|
if !used.Has(port) {
|
||||||
used.Insert(port)
|
used.Insert(port)
|
||||||
return port
|
return port
|
||||||
|
@ -24,6 +24,30 @@ import (
|
|||||||
"github.com/fatedier/frp/pkg/util/util"
|
"github.com/fatedier/frp/pkg/util/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type HTTPAuthWrapper struct {
|
||||||
|
h http.Handler
|
||||||
|
user string
|
||||||
|
passwd string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHTTPBasicAuthWrapper(h http.Handler, user, passwd string) http.Handler {
|
||||||
|
return &HTTPAuthWrapper{
|
||||||
|
h: h,
|
||||||
|
user: user,
|
||||||
|
passwd: passwd,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (aw *HTTPAuthWrapper) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
user, passwd, hasAuth := r.BasicAuth()
|
||||||
|
if (aw.user == "" && aw.passwd == "") || (hasAuth && user == aw.user && passwd == aw.passwd) {
|
||||||
|
aw.h.ServeHTTP(w, r)
|
||||||
|
} else {
|
||||||
|
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
|
||||||
|
http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type HTTPAuthMiddleware struct {
|
type HTTPAuthMiddleware struct {
|
||||||
user string
|
user string
|
||||||
passwd string
|
passwd string
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"golang.org/x/net/websocket"
|
"golang.org/x/net/websocket"
|
||||||
)
|
)
|
||||||
@ -49,6 +50,15 @@ func NewWebsocketListener(ln net.Listener) (wl *WebsocketListener) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ListenWebsocket(bindAddr string, bindPort int) (*WebsocketListener, error) {
|
||||||
|
tcpLn, err := net.Listen("tcp", net.JoinHostPort(bindAddr, strconv.Itoa(bindPort)))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
l := NewWebsocketListener(tcpLn)
|
||||||
|
return l, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (p *WebsocketListener) Accept() (net.Conn, error) {
|
func (p *WebsocketListener) Accept() (net.Conn, error) {
|
||||||
c, ok := <-p.acceptCh
|
c, ok := <-p.acceptCh
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -20,7 +20,7 @@ import (
|
|||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
mathrand "math/rand/v2"
|
mathrand "math/rand"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -47,6 +47,16 @@ func RandIDWithLen(idLen int) (id string, err error) {
|
|||||||
return id[:idLen], nil
|
return id[:idLen], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RandIDWithRandLen return a rand string with length between [start, end).
|
||||||
|
func RandIDWithRandLen(start, end int) (id string, err error) {
|
||||||
|
if start >= end {
|
||||||
|
err = fmt.Errorf("start should be less than end")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
idLen := mathrand.Intn(end-start) + start
|
||||||
|
return RandIDWithLen(idLen)
|
||||||
|
}
|
||||||
|
|
||||||
func GetAuthKey(token string, timestamp int64) (key string) {
|
func GetAuthKey(token string, timestamp int64) (key string) {
|
||||||
md5Ctx := md5.New()
|
md5Ctx := md5.New()
|
||||||
md5Ctx.Write([]byte(token))
|
md5Ctx.Write([]byte(token))
|
||||||
@ -124,7 +134,7 @@ func RandomSleep(duration time.Duration, minRatio, maxRatio float64) time.Durati
|
|||||||
if max <= min {
|
if max <= min {
|
||||||
n = min
|
n = min
|
||||||
} else {
|
} else {
|
||||||
n = mathrand.Int64N(max-min) + min
|
n = mathrand.Int63n(max-min) + min
|
||||||
}
|
}
|
||||||
d := duration * time.Duration(n) / time.Duration(1000)
|
d := duration * time.Duration(n) / time.Duration(1000)
|
||||||
time.Sleep(d)
|
time.Sleep(d)
|
||||||
|
@ -14,6 +14,48 @@ func TestRandId(t *testing.T) {
|
|||||||
assert.Equal(16, len(id))
|
assert.Equal(16, len(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRandIDWithRandLen(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
start int
|
||||||
|
end int
|
||||||
|
expectErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "start and end are equal",
|
||||||
|
start: 5,
|
||||||
|
end: 5,
|
||||||
|
expectErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "start is less than end",
|
||||||
|
start: 5,
|
||||||
|
end: 10,
|
||||||
|
expectErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "start is greater than end",
|
||||||
|
start: 10,
|
||||||
|
end: 5,
|
||||||
|
expectErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
id, err := RandIDWithRandLen(tt.start, tt.end)
|
||||||
|
if tt.expectErr {
|
||||||
|
assert.Error(err)
|
||||||
|
} else {
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.GreaterOrEqual(len(id), tt.start)
|
||||||
|
assert.Less(len(id), tt.end)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetAuthKey(t *testing.T) {
|
func TestGetAuthKey(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
key := GetAuthKey("1234", 1488720000)
|
key := GetAuthKey("1234", 1488720000)
|
||||||
|
@ -14,8 +14,34 @@
|
|||||||
|
|
||||||
package version
|
package version
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
var version = "0.54.0"
|
var version = "0.54.0"
|
||||||
|
|
||||||
func Full() string {
|
func Full() string {
|
||||||
return version
|
return version
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getSubVersion(v string, position int) int64 {
|
||||||
|
arr := strings.Split(v, ".")
|
||||||
|
if len(arr) < 3 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
res, _ := strconv.ParseInt(arr[position], 10, 64)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func Proto(v string) int64 {
|
||||||
|
return getSubVersion(v, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Major(v string) int64 {
|
||||||
|
return getSubVersion(v, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Minor(v string) int64 {
|
||||||
|
return getSubVersion(v, 2)
|
||||||
|
}
|
||||||
|
53
pkg/util/version/version_test.go
Normal file
53
pkg/util/version/version_test.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// Copyright 2016 fatedier, fatedier@gmail.com
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package version
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFull(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
version := Full()
|
||||||
|
arr := strings.Split(version, ".")
|
||||||
|
assert.Equal(3, len(arr))
|
||||||
|
|
||||||
|
proto, err := strconv.ParseInt(arr[0], 10, 64)
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.True(proto >= 0)
|
||||||
|
|
||||||
|
major, err := strconv.ParseInt(arr[1], 10, 64)
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.True(major >= 0)
|
||||||
|
|
||||||
|
minor, err := strconv.ParseInt(arr[2], 10, 64)
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.True(minor >= 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVersion(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
proto := Proto(Full())
|
||||||
|
major := Major(Full())
|
||||||
|
minor := Minor(Full())
|
||||||
|
parseVersion := fmt.Sprintf("%d.%d.%d", proto, major, minor)
|
||||||
|
version := Full()
|
||||||
|
assert.Equal(parseVersion, version)
|
||||||
|
}
|
@ -15,7 +15,8 @@
|
|||||||
package wait
|
package wait
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand/v2"
|
"math/rand"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fatedier/frp/pkg/util/util"
|
"github.com/fatedier/frp/pkg/util/util"
|
||||||
@ -173,3 +174,21 @@ func Until(f func(), period time.Duration, stopCh <-chan struct{}) {
|
|||||||
return period
|
return period
|
||||||
}), true, stopCh)
|
}), true, stopCh)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MergeAndCloseOnAnyStopChannel[T any](upstreams ...<-chan T) <-chan T {
|
||||||
|
out := make(chan T)
|
||||||
|
closeOnce := sync.Once{}
|
||||||
|
for _, upstream := range upstreams {
|
||||||
|
ch := upstream
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case <-ch:
|
||||||
|
closeOnce.Do(func() {
|
||||||
|
close(out)
|
||||||
|
})
|
||||||
|
case <-out:
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user