Files
trojan-go/common/net.go
T

180 lines
3.6 KiB
Go

package common
import (
"encoding/binary"
"fmt"
"io"
"net"
"strconv"
)
type AddressType byte
const (
IPv4 AddressType = 1
DomainName AddressType = 3
IPv6 AddressType = 4
)
type Address struct {
net.Addr
DomainName string
Port int
NetworkType string
net.IP
AddressType
}
func (a *Address) String() string {
switch a.AddressType {
case IPv4:
return fmt.Sprintf("%s:%d", a.IP.String(), a.Port)
case IPv6:
return fmt.Sprintf("[%s]:%d", a.IP.String(), a.Port)
case DomainName:
return fmt.Sprintf("%s:%d", a.DomainName, a.Port)
default:
return ""
}
}
func (a *Address) Network() string {
return a.NetworkType
}
func (a *Address) ResolveIP() (net.IP, error) {
if a.AddressType == IPv4 || a.AddressType == IPv6 {
return a.IP, nil
}
if a.IP != nil {
return a.IP, nil
}
addr, err := net.ResolveIPAddr("ip", a.DomainName)
if err != nil {
return nil, err
}
a.IP = addr.IP
return addr.IP, nil
}
func NewAddress(host string, port int, network string) *Address {
if ip := net.ParseIP(host); ip != nil {
if ip.To4() != nil {
return &Address{
IP: ip,
Port: port,
AddressType: IPv4,
NetworkType: network,
}
}
return &Address{
IP: ip,
Port: port,
AddressType: IPv6,
NetworkType: network,
}
}
return &Address{
DomainName: host,
Port: port,
AddressType: DomainName,
NetworkType: network,
}
}
func (a *Address) Marshal(r io.Reader) error {
byteBuf := [1]byte{}
_, err := r.Read(byteBuf[:])
if err != nil {
return NewError("Cannot read atype").Base(err)
}
a.AddressType = AddressType(byteBuf[0])
switch a.AddressType {
case IPv4:
var buf [6]byte
_, err := r.Read(buf[:])
if err != nil {
return NewError("Failed to read ipv4").Base(err)
}
a.IP = buf[0:4]
a.Port = int(binary.BigEndian.Uint16(buf[4:6]))
case IPv6:
var buf [18]byte
_, err := r.Read(buf[:])
if err != nil {
return NewError("Failed to read ipv6").Base(err)
}
a.IP = buf[0:16]
a.Port = int(binary.BigEndian.Uint16(buf[16:18]))
case DomainName:
_, err := r.Read(byteBuf[:])
length := byteBuf[0]
if err != nil {
return NewError("Failed to read length")
}
buf := make([]byte, length+2)
_, err = r.Read(buf)
if err != nil {
return NewError("Failed to read domain")
}
//the fucking browser uses IP as a domain name sometimes
host := buf[0:length]
if ip := net.ParseIP(string(host)); ip != nil {
a.IP = ip
if ip.To4() != nil {
a.AddressType = IPv4
} else {
a.AddressType = IPv6
}
} else {
a.DomainName = string(host)
}
a.Port = int(binary.BigEndian.Uint16(buf[length : length+2]))
default:
return NewError("Invalid ATYPE " + strconv.FormatInt(int64(a.AddressType), 10))
}
return nil
}
func (a *Address) Unmarshal(w io.Writer) error {
_, err := w.Write([]byte{byte(a.AddressType)})
switch a.AddressType {
case DomainName:
w.Write([]byte{byte((len(a.DomainName)))})
_, err = w.Write([]byte(a.DomainName))
case IPv4:
_, err = w.Write(a.IP.To4())
case IPv6:
_, err = w.Write(a.IP.To16())
default:
return NewError("Invalid ATYPE " + strconv.FormatInt(int64(a.AddressType), 10))
}
if err != nil {
return err
}
port := [2]byte{}
binary.BigEndian.PutUint16(port[:], uint16(a.Port))
_, err = w.Write(port[:])
return err
}
const (
KiB = 1024
MiB = KiB * 1024
GiB = MiB * 1024
)
func HumanFriendlyTraffic(bytes uint64) string {
if bytes <= KiB {
return fmt.Sprintf("%d B", bytes)
}
if bytes <= MiB {
return fmt.Sprintf("%.2f KiB", float32(bytes)/KiB)
}
if bytes <= GiB {
return fmt.Sprintf("%.2f MiB", float32(bytes)/MiB)
}
return fmt.Sprintf("%.2f GiB", float32(bytes)/GiB)
}