More protocols
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package aprs
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
@@ -46,6 +47,25 @@ func (a Address) Secret() int16 {
|
||||
return h & 0x7fff
|
||||
}
|
||||
|
||||
func (a Address) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(a.String())
|
||||
}
|
||||
|
||||
func (a *Address) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
p, err := ParseAddress(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.Call = p.Call
|
||||
a.SSID = p.SSID
|
||||
a.IsRepeated = p.IsRepeated
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseAddress(s string) (Address, error) {
|
||||
r := strings.HasSuffix(s, "*")
|
||||
if r {
|
||||
|
||||
188
protocol/aprs/aprsis/proxy.go
Normal file
188
protocol/aprs/aprsis/proxy.go
Normal file
@@ -0,0 +1,188 @@
|
||||
package aprsis
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"git.maze.io/go/ham/protocol"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultListenAddr = ":14580"
|
||||
DefaultServerAddr = "rotate.aprs2.net:14580"
|
||||
)
|
||||
|
||||
type Proxy struct {
|
||||
Logger *logrus.Logger
|
||||
Filter string
|
||||
server string
|
||||
listen net.Listener
|
||||
packets chan *protocol.Packet
|
||||
}
|
||||
|
||||
func NewProxy(listen, server string) (*Proxy, error) {
|
||||
if _, err := net.ResolveTCPAddr("tcp", server); err != nil {
|
||||
return nil, fmt.Errorf("aprsis: error resolving %q: %v", server, err)
|
||||
}
|
||||
|
||||
listenAddr, err := net.ResolveTCPAddr("tcp", listen)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("aprsis: error listening on %s: %v", listen, err)
|
||||
}
|
||||
|
||||
listener, err := net.ListenTCP("tcp", listenAddr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("aprsis: error listening on %s: %v", listen, err)
|
||||
}
|
||||
|
||||
proxy := &Proxy{
|
||||
Logger: logrus.New(),
|
||||
server: server,
|
||||
listen: listener,
|
||||
}
|
||||
go proxy.accept()
|
||||
|
||||
return proxy, nil
|
||||
}
|
||||
|
||||
func (proxy *Proxy) Close() error {
|
||||
if proxy.packets != nil {
|
||||
close(proxy.packets)
|
||||
proxy.packets = nil
|
||||
}
|
||||
return proxy.listen.Close()
|
||||
}
|
||||
|
||||
func (proxy *Proxy) RawPackets() <-chan *protocol.Packet {
|
||||
if proxy.packets == nil {
|
||||
proxy.packets = make(chan *protocol.Packet, 16)
|
||||
}
|
||||
return proxy.packets
|
||||
}
|
||||
|
||||
func (proxy *Proxy) accept() {
|
||||
for {
|
||||
client, err := proxy.listen.Accept()
|
||||
if err != nil {
|
||||
proxy.Logger.Errorf("aprs-is proxy: error accepting client: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
go proxy.handle(client)
|
||||
}
|
||||
}
|
||||
|
||||
func (proxy *Proxy) handle(client net.Conn) {
|
||||
defer func() { _ = client.Close() }()
|
||||
|
||||
host, _, _ := net.SplitHostPort(client.RemoteAddr().String())
|
||||
proxy.Logger.Infof("aprs-is proxy[%s]: new connection", host)
|
||||
|
||||
server, err := net.Dial("tcp", proxy.server)
|
||||
if err != nil {
|
||||
proxy.Logger.Warnf("aprs-is proxy[%s]: can't connecto to APRS-IS server %s: %v", host, proxy.server, err)
|
||||
return
|
||||
}
|
||||
defer func() { _ = server.Close() }()
|
||||
|
||||
var (
|
||||
wait sync.WaitGroup
|
||||
call string
|
||||
)
|
||||
wait.Go(func() { proxy.proxy(client, server, host, "->", &call) })
|
||||
wait.Go(func() { proxy.proxy(server, client, host, "<-", nil) })
|
||||
wait.Wait()
|
||||
}
|
||||
|
||||
func (proxy *Proxy) proxy(dst, src net.Conn, host, dir string, call *string) {
|
||||
defer func() {
|
||||
if tcp, ok := dst.(*net.TCPConn); ok {
|
||||
_ = tcp.CloseWrite()
|
||||
} else {
|
||||
_ = dst.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
reader := bufio.NewReader(src)
|
||||
for {
|
||||
line, err := reader.ReadBytes('\n')
|
||||
if err != nil {
|
||||
proxy.Logger.Warnf("aprs-is proxy[%s]: %s read error: %v", host, src.RemoteAddr(), err)
|
||||
return
|
||||
}
|
||||
|
||||
// proxy to remote unaltered
|
||||
if len(line) > 0 {
|
||||
if _, err = dst.Write(line); err != nil {
|
||||
proxy.Logger.Warnf("aprs-is proxy[%s]: %s write error: %v", host, dst.RemoteAddr(), err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// parse line
|
||||
line = bytes.TrimRight(line, "\r\n")
|
||||
if len(line) > 0 {
|
||||
proxy.Logger.Tracef("aprs-is proxy[%s]: %s %s", host, dir, string(line))
|
||||
|
||||
if call != nil && strings.HasPrefix(string(line), "# logresp ") {
|
||||
// server responds to client login
|
||||
part := strings.SplitN(string(line), " ", 5)
|
||||
if len(part) > 4 && part[3] == "verified," {
|
||||
*call = part[2]
|
||||
proxy.Logger.Infof("aprs-is proxy[%s]: logged in as %s", host, *call)
|
||||
|
||||
if proxy.Filter != "" {
|
||||
proxy.Logger.Tracef("aprs-is proxy[%s]: %s filter %s", host, dir, proxy.Filter)
|
||||
if _, err = fmt.Fprintf(src, "filter %s\r\n", proxy.Filter); err != nil {
|
||||
proxy.Logger.Warnf("aprs-is proxy[%s]: %s write error: %v", host, src.RemoteAddr(), err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !isCommand(line) {
|
||||
proxy.handleRawPacket(line)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (proxy *Proxy) handleRawPacket(data []byte) {
|
||||
if proxy.packets == nil {
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case proxy.packets <- &protocol.Packet{
|
||||
Protocol: "aprs",
|
||||
Raw: data,
|
||||
}:
|
||||
default:
|
||||
proxy.Logger.Warn("aprs-is proxy: raw packet channel full, dropping packet")
|
||||
}
|
||||
}
|
||||
|
||||
func isCommand(line []byte) bool {
|
||||
if len(line) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
if line[0] == '#' {
|
||||
return true
|
||||
}
|
||||
|
||||
if i := bytes.IndexByte(line, ' '); i > -1 {
|
||||
switch strings.ToLower(string(line[:i])) {
|
||||
case "user", "filter":
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
@@ -140,7 +140,7 @@ func (o OmniDFStrength) Directivity() float64 {
|
||||
// Packet contains an APRS packet.
|
||||
type Packet struct {
|
||||
// Raw packet (as captured from the air or APRS-IS).
|
||||
Raw string `json:"raw"`
|
||||
Raw string `json:"-"`
|
||||
|
||||
// Src is the source address.
|
||||
Src Address `json:"src"`
|
||||
|
||||
Reference in New Issue
Block a user