hysteria/extras/network/frame.go
Niko Marmeladkov da8366eb8a
feat: L3 VPN tunnel, FileMask noise, Hysteria outbound
- Network: Layer 3 IP tunnel over QUIC with TUN interfaces and IP pool
- FileMask: new noise/obfuscation layer masking traffic as encrypted file downloads
- Hysteria outbound: chain Hysteria servers via pluggable outbound
2026-06-16 16:07:55 +03:00

73 lines
1.7 KiB
Go

package network
import (
"encoding/binary"
"fmt"
"io"
"net"
"github.com/apernet/quic-go"
)
type FrameType byte
const (
FrameAuth FrameType = 0x01
FrameAuthOK FrameType = 0x02
FrameAuthErr FrameType = 0x03
FrameData FrameType = 0x04
FrameKeepalive FrameType = 0x05
)
type Frame struct {
Type FrameType
Payload []byte
}
func SendFrame(stream *quic.Stream, f *Frame) error {
buf := make([]byte, 4+1+len(f.Payload))
binary.BigEndian.PutUint32(buf[:4], uint32(1+len(f.Payload)))
buf[4] = byte(f.Type)
copy(buf[5:], f.Payload)
_, err := stream.Write(buf)
return err
}
func ReceiveFrame(stream *quic.Stream) (*Frame, error) {
var lenBuf [4]byte
if _, err := io.ReadFull(stream, lenBuf[:]); err != nil {
return nil, err
}
frameLen := binary.BigEndian.Uint32(lenBuf[:])
if frameLen < 1 || frameLen > 65535 {
return nil, fmt.Errorf("invalid frame length: %d", frameLen)
}
frameData := make([]byte, frameLen)
if _, err := io.ReadFull(stream, frameData); err != nil {
return nil, err
}
return &Frame{
Type: FrameType(frameData[0]),
Payload: frameData[1:],
}, nil
}
func SendAuth(stream *quic.Stream, token string) error {
return SendFrame(stream, &Frame{Type: FrameAuth, Payload: []byte(token)})
}
func SendAuthOK(stream *quic.Stream, assignedIP net.IP) error {
return SendFrame(stream, &Frame{Type: FrameAuthOK, Payload: assignedIP.To4()})
}
func SendAuthErr(stream *quic.Stream, reason string) error {
return SendFrame(stream, &Frame{Type: FrameAuthErr, Payload: []byte(reason)})
}
func SendData(stream *quic.Stream, pkt []byte) error {
return SendFrame(stream, &Frame{Type: FrameData, Payload: pkt})
}
func SendKeepalive(stream *quic.Stream) error {
return SendFrame(stream, &Frame{Type: FrameKeepalive})
}