Skip to content

Commit

Permalink
Refactored listener code, tests dont work atm
Browse files Browse the repository at this point in the history
  • Loading branch information
realDragonium committed Jul 5, 2021
1 parent aac5121 commit f59f4ac
Show file tree
Hide file tree
Showing 17 changed files with 329 additions and 323 deletions.
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ RUN go build -tags netgo

FROM scratch
WORKDIR /
COPY --from=builder /ultraviolet/UltraViolet ./
ENTRYPOINT [ "./UltraViolet" ]
COPY --from=builder /ultraviolet/Ultraviolet ./
ENTRYPOINT [ "./Ultraviolet" ]
8 changes: 2 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
# UltraViolet
# Ultraviolet
## What is it
[Infrared](https://github.com/haveachin/infrared) but different. Not even sure or this will be a real production ready product some day, its a different structure I want to try.


## Some notes
### Tableflip
This has implemented [tableflip](https://github.com/cloudflare/tableflip) which should make it able to reload/restart UltraViolet without closing existing connections on Linux and macOS. UltraViolet should still be usable on windows (testing purposes only pls).
This has implemented [tableflip](https://github.com/cloudflare/tableflip) which should make it able to reload/restart Ultraviolet without closing existing connections on Linux and macOS. Ultraviolet should still be usable on windows (testing purposes only pls).
Check their [documentation](https://pkg.go.dev/github.com/cloudflare/tableflip) to know what or how.


## Lists on things to try out
- https://github.com/cenkalti/backoff
70 changes: 70 additions & 0 deletions config/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package config

import "github.com/realDragonium/Ultraviolet/mc"

type ServerConfig struct {
BackendCfg BackendConnConfig `json:"backend"`
ListenCfg ListenConfig `json:"listen"`
FallOverCfg FallOverConfig `json:"fallOver"`

ConnLimitBackend int `json:"connPerSec"`
}

type BackendConnConfig struct {
ProxyBind string `json:"proxyBind"`
ProxyTo string `json:"proxyTo"`
SendProxyProtocol bool `json:"sendProxyProtocol"`
RealIP bool `json:"realIp"`
}

type ListenConfig struct {
MainDomain string `json:"mainDomain"`
ExtraDomains []string `json:"extraDomains"`
ListenTo string `json:"listenTo"`
}

type FallOverConfig struct {
DisconnectMessage string `json:"disconnectMessage"`
OfflineStatus mc.AnotherStatusResponse `json:"offlineStatus"`
}

func DefaultServerConfig() ServerConfig {
return ServerConfig{
BackendCfg: BackendConnConfig{
ProxyBind: "0.0.0.0",
ProxyTo: ":25566",
},
ListenCfg: ListenConfig{
MainDomain: "localhost",
ListenTo: ":25565",
},
FallOverCfg: FallOverConfig{
DisconnectMessage: "Sorry {{username}}, but the server is offline.",
OfflineStatus: mc.AnotherStatusResponse{
Name: "Ultraviolet",
Protocol: 755,
Description: "Some broken proxy",
},
},
ConnLimitBackend: 5,
}
}

type UltravioletConfig struct {
NumberOfWorkers int `json:"numberOfWorkers"`
ReceiveProxyProtocol bool `json:"receiveProxyProtocol"`

DefaultStatus mc.AnotherStatusResponse `json:"defaultStatus"`
}

func DefaultUltravioletConfig() UltravioletConfig {
return UltravioletConfig{
NumberOfWorkers: 5,
ReceiveProxyProtocol: false,
DefaultStatus: mc.AnotherStatusResponse{
Name: "Ultraviolet",
Protocol: 755,
Description: "Some broken proxy",
},
}
}
232 changes: 88 additions & 144 deletions conn/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,43 @@ import (
"log"
"net"

"github.com/realDragonium/UltraViolet/mc"
"github.com/realDragonium/Ultraviolet/mc"
)

func NewListener(listener net.Listener) Listener {
return Listener{
listener: listener,
LoginReqCh: make(chan LoginRequest),
LoginAnsCh: make(chan LoginAnswer),
StatusReqCh: make(chan StatusRequest),
StatusAnsCh: make(chan StatusAnswer),
}
type ConnAction byte
type ConnType byte

const (
PROXY ConnAction = iota
DISCONNECT
SEND_STATUS
CLOSE
)

const (
STATUS ConnType = iota + 1
LOGIN
)

type ConnRequest struct {
Type ConnType
ServerAddr string
Username string
Ip net.Addr
Ch chan ConnAnswer
}

type Listener struct {
listener net.Listener
LoginReqCh chan LoginRequest
LoginAnsCh chan LoginAnswer
StatusReqCh chan StatusRequest
StatusAnsCh chan StatusAnswer
type ConnAnswer struct {
ServerConn McConn
DisconMessage mc.Packet
Action ConnAction
StatusPk mc.Packet
NotifyClosed chan struct{}
}

func (l Listener) Serve() {
func Serve(listener net.Listener, reqCh chan ConnRequest) {
for {
conn, err := l.listener.Accept()
conn, err := listener.Accept()
if err != nil {
if errors.Is(err, net.ErrClosed) {
log.Printf("net.Listener was closed, shutting down listener")
Expand All @@ -39,101 +52,74 @@ func (l Listener) Serve() {
log.Println(err)
continue
}
go l.ReadConnection(conn)
go ReadConnection(conn, reqCh)
}
}

func (l Listener) ReadConnection(c net.Conn) {
// Rewrite this
conn := NewHandshakeConn(c, c.RemoteAddr())
packet, err := conn.ReadPacket()
func ReadConnection(c net.Conn, reqCh chan ConnRequest) {
// Rewrite connection code
conn := NewMcConn(c)
handshakePacket, err := conn.ReadPacket()
remoteAddr := c.RemoteAddr()
if err != nil {
log.Printf("Error while reading handshake packet: %v", err)
}
handshake, err := mc.UnmarshalServerBoundHandshake(packet)
handshake, err := mc.UnmarshalServerBoundHandshake(handshakePacket)
if err != nil {
log.Printf("Error while unmarshaling handshake packet: %v", err)
}
conn.HandshakePacket = packet
conn.Handshake = handshake

switch handshake.NextState {
case mc.ServerBoundHandshakeStatusState:
l.DoStatusSequence(conn)
case mc.ServerBoundHandshakeLoginState:
l.DoLoginSequence(conn)
default:

if handshake.NextState != mc.HandshakeLoginState && handshake.NextState != mc.HandshakeStatusState {
conn.netConn.Close()
return
}
}

type LoginRequest struct {
ServerAddr string
Username string
Ip net.Addr
}
type LoginAnswer struct {
ServerConn net.Conn
DisconMessage mc.Packet
Action ConnAction
NotifyClosed chan struct{}
}
type ConnAction byte

const (
PROXY ConnAction = iota
DISCONNECT
SEND_STATUS
CLOSE
)

func (l Listener) DoLoginSequence(conn HandshakeConn) {
// Rewrite this
packet, err := conn.ReadPacket()
if err != nil {
log.Printf("Error while reading login start packet: %v", err)
isLoginReq := false
if handshake.NextState == mc.HandshakeLoginState {
isLoginReq = true
}
loginStart, err := mc.UnmarshalServerBoundLoginStart(packet)
if err != nil {
log.Printf("Error while unmarshaling login start packet: %v", err)

ansCh := make(chan ConnAnswer)
req := ConnRequest{
Ch: ansCh,
}
l.LoginReqCh <- LoginRequest{
ServerAddr: string(conn.Handshake.ServerAddress),
Username: string(loginStart.Name),
Ip: conn.RemoteAddr(),
var loginPacket mc.Packet
if isLoginReq {
loginPacket, err := conn.ReadPacket()
if err != nil {
log.Printf("Error while reading login start packet: %v", err)
}
loginStart, err := mc.UnmarshalServerBoundLoginStart(loginPacket)
if err != nil {
log.Printf("Error while unmarshaling login start packet: %v", err)
}
req = ConnRequest{
ServerAddr: string(handshake.ServerAddress),
Username: string(loginStart.Name),
Ip: remoteAddr,
Ch: ansCh,
}
}
ans := <-l.LoginAnsCh
reqCh <- req
ans := <-ansCh

switch ans.Action {
case PROXY:
bytes, _ := conn.HandshakePacket.Marshal()
ans.ServerConn.Write(bytes)
bytes, _ = packet.Marshal()
ans.ServerConn.Write(bytes)
go ProxyConnections(conn.netConn, ans.ServerConn, ans.NotifyClosed)
serverConn := ans.ServerConn
serverConn.WritePacket(handshakePacket)
if isLoginReq {
serverConn.WritePacket(loginPacket)
}
go func() {
io.Copy(serverConn.netConn, conn.netConn)
conn.netConn.Close()
}()
io.Copy(conn.netConn, serverConn.netConn)
serverConn.netConn.Close()
ans.NotifyClosed <- struct{}{}
case DISCONNECT:
conn.WritePacket(ans.DisconMessage)
conn.netConn.Close()
case CLOSE:
conn.netConn.Close()
}
}

type StatusRequest struct{}
type StatusAnswer struct {
Action ConnAction
ServerConn net.Conn
StatusPk mc.Packet
NotifyClosed chan struct{}
}

func (l Listener) DoStatusSequence(conn HandshakeConn) {
l.StatusReqCh <- StatusRequest{}
ans := <-l.StatusAnsCh
switch ans.Action {
case PROXY:
bytes, _ := conn.HandshakePacket.Marshal()
ans.ServerConn.Write(bytes)
go ProxyConnections(conn.netConn, ans.ServerConn, ans.NotifyClosed)
case SEND_STATUS:
conn.ReadPacket()
conn.WritePacket(ans.StatusPk)
Expand All @@ -143,72 +129,30 @@ func (l Listener) DoStatusSequence(conn HandshakeConn) {
case CLOSE:
conn.netConn.Close()
}
}

func ProxyConnections(client, server net.Conn, closeCh chan struct{}) {
go func() {
io.Copy(server, client)
client.Close()
}()
io.Copy(client, server)
server.Close()
closeCh <- struct{}{}
}

// handshake, err := mc.ReadHandshake(byteReader)
// if err != nil {
// return
// }

// packetBuffer := make([]byte, mc.MaxPacketSize)
// conn.Read(packetBuffer)
// byteReader := bytes.NewReader(packetBuffer)
// packet, err := mc.ReadPacketOld(byteReader)

// func triedSomething (){
// packetBuffer := make([]byte, mc.MaxPacketSize)
// conn.Read(packetBuffer)

// packetSize, sizeLength, err := mc.ReadPacketSize_Bytes(packetBuffer)
// if errors.Is(err, mc.ErrVarIntSize) || packetSize > mc.MaxPacketSize {
// conn.Close()
// return
// }
// packetBytes := packetBuffer[sizeLength:packetSize]

// emptyFunc(packetBytes)
// }
// func emptyFunc(something ...interface{}) {

// }

func NewHandshakeConn(conn net.Conn, remoteAddr net.Addr) HandshakeConn {
return HandshakeConn{
func NewMcConn(conn net.Conn) McConn {
return McConn{
netConn: conn,
reader: bufio.NewReader(conn),
addr: remoteAddr,
}
}

type HandshakeConn struct {
type McConn struct {
netConn net.Conn
reader mc.DecodeReader
addr net.Addr

Handshake mc.ServerBoundHandshake
HandshakePacket mc.Packet
}

func (hsConn HandshakeConn) RemoteAddr() net.Addr {
return hsConn.addr
}

func (conn HandshakeConn) ReadPacket() (mc.Packet, error) {
func (conn McConn) ReadPacket() (mc.Packet, error) {
return mc.ReadPacket(conn.reader)
}

func (conn HandshakeConn) WritePacket(p mc.Packet) error {
pk, _ := p.Marshal()
_, err := conn.netConn.Write(pk)
func (conn McConn) WritePacket(p mc.Packet) error {
pk, err := p.Marshal()
if err != nil {
return errors.New("some idiot (probably me) is sending an invalid packet through here")
}
_, err = conn.netConn.Write(pk)
return err
}
Loading

0 comments on commit f59f4ac

Please sign in to comment.