Skip to content

Commit

Permalink
Move the service into shadowsocks.go.
Browse files Browse the repository at this point in the history
  • Loading branch information
sbruens committed Sep 6, 2024
1 parent 6e330fa commit 2738b45
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 126 deletions.
4 changes: 2 additions & 2 deletions cmd/outline-ss-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ func (s *SSServer) runConfig(config Config) (func() error, error) {
ciphers := service.NewCipherList()
ciphers.Update(cipherList)

ssService, err := service.NewService(
ssService, err := service.NewShadowsocksService(
service.WithCiphers(ciphers),
service.WithNatTimeout(s.natTimeout),
service.WithMetrics(s.serviceMetrics),
Expand All @@ -243,7 +243,7 @@ func (s *SSServer) runConfig(config Config) (func() error, error) {
if err != nil {
return fmt.Errorf("failed to create cipher list from config: %v", err)
}
ssService, err := service.NewService(
ssService, err := service.NewShadowsocksService(
service.WithCiphers(ciphers),
service.WithNatTimeout(s.natTimeout),
service.WithMetrics(s.serviceMetrics),
Expand Down
123 changes: 0 additions & 123 deletions service/service.go

This file was deleted.

112 changes: 111 additions & 1 deletion service/shadowsocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,119 @@

package service

import "time"
import (
"context"
"net"
"time"

"github.com/Jigsaw-Code/outline-sdk/transport"
)

const (
// 59 seconds is most common timeout for servers that do not respond to invalid requests
tcpReadTimeout time.Duration = 59 * time.Second

// A UDP NAT timeout of at least 5 minutes is recommended in RFC 4787 Section 4.3.
defaultNatTimeout time.Duration = 5 * time.Minute
)

// ShadowsocksConnMetrics is used to report Shadowsocks related metrics on connections.
type ShadowsocksConnMetrics interface {
AddCipherSearch(accessKeyFound bool, timeToCipher time.Duration)
}

type ServiceMetrics interface {
UDPMetrics
AddOpenTCPConnection(conn net.Conn) TCPConnMetrics
AddCipherSearch(proto string, accessKeyFound bool, timeToCipher time.Duration)
}

type Service interface {
HandleStream(ctx context.Context, conn transport.StreamConn)
HandlePacket(conn net.PacketConn)
}

// Option is a Shadowsocks service constructor option.
type Option func(s *ssService)

type ssService struct {
m ServiceMetrics
ciphers CipherList
natTimeout time.Duration
replayCache *ReplayCache

sh StreamHandler
ph PacketHandler
}

// NewShadowsocksService creates a new service
func NewShadowsocksService(opts ...Option) (Service, error) {
s := &ssService{}

for _, opt := range opts {
opt(s)
}

if s.natTimeout == 0 {
s.natTimeout = defaultNatTimeout
}
return s, nil
}

// WithCiphers option function.
func WithCiphers(ciphers CipherList) Option {
return func(s *ssService) {
s.ciphers = ciphers
}
}

// WithMetrics option function.
func WithMetrics(metrics ServiceMetrics) Option {
return func(s *ssService) {
s.m = metrics
}
}

// WithReplayCache option function.
func WithReplayCache(replayCache *ReplayCache) Option {
return func(s *ssService) {
s.replayCache = replayCache
}
}

// WithNatTimeout option function.
func WithNatTimeout(natTimeout time.Duration) Option {
return func(s *ssService) {
s.natTimeout = natTimeout
}
}

// HandleStream handles a Shadowsocks stream-based connection.
func (s *ssService) HandleStream(ctx context.Context, conn transport.StreamConn) {
if s.sh == nil {
authFunc := NewShadowsocksStreamAuthenticator(s.ciphers, s.replayCache, &ssConnMetrics{ServiceMetrics: s.m, proto: "tcp"})
// TODO: Register initial data metrics at zero.
s.sh = NewStreamHandler(authFunc, tcpReadTimeout)
}
connMetrics := s.m.AddOpenTCPConnection(conn)
s.sh.Handle(ctx, conn, connMetrics)
}

// HandlePacket handles a Shadowsocks packet connection.
func (s *ssService) HandlePacket(conn net.PacketConn) {
if s.ph == nil {
s.ph = NewPacketHandler(s.natTimeout, s.ciphers, s.m, &ssConnMetrics{ServiceMetrics: s.m, proto: "udp"})
}
s.ph.Handle(conn)
}

type ssConnMetrics struct {
ServiceMetrics
proto string
}

var _ ShadowsocksConnMetrics = (*ssConnMetrics)(nil)

func (cm *ssConnMetrics) AddCipherSearch(accessKeyFound bool, timeToCipher time.Duration) {
cm.ServiceMetrics.AddCipherSearch(cm.proto, accessKeyFound, timeToCipher)
}

0 comments on commit 2738b45

Please sign in to comment.