blob: 41efcdedc0bee6b801ce1127be2a1a59306bcbbf [file] [log] [blame]
Tim Windelschmidt6d33a432025-02-04 14:34:25 +01001// Copyright The Monogon Project Authors.
2// SPDX-License-Identifier: Apache-2.0
3
Serge Bazanskibe742842022-04-04 13:18:50 +02004package main
5
6import (
7 "context"
8 "fmt"
9 "net"
10
Tim Windelschmidt9f21f532024-05-07 15:14:20 +020011 "source.monogon.dev/osbase/supervisor"
Jan Schär341cd422025-09-04 10:33:21 +020012 "source.monogon.dev/osbase/test/socksproxy"
Serge Bazanskibe742842022-04-04 13:18:50 +020013)
14
Tim Windelschmidta3cd52c2024-04-18 23:21:16 +020015// SOCKSPort is the port at which nanoswitch listens for SOCKS conenctions.
16//
Tim Windelschmidt9f21f532024-05-07 15:14:20 +020017// ONCHANGE(//metropolis/test/launch:cluster.go): port must be kept in sync
Serge Bazanskibe742842022-04-04 13:18:50 +020018const SOCKSPort uint16 = 1080
19
20// socksHandler implements a socksproxy.Handler which permits and logs
21// connections to the nanoswitch network.
22type socksHandler struct{}
23
24func (s *socksHandler) Connect(ctx context.Context, req *socksproxy.ConnectRequest) *socksproxy.ConnectResponse {
25 logger := supervisor.Logger(ctx)
Lorenz Brun08fd1cb2025-02-10 19:11:17 +010026 var target string
27 var addr net.IP
28 if req.Hostname == "" {
29 target = net.JoinHostPort(req.Address.String(), fmt.Sprintf("%d", req.Port))
30 if req.Address.To4() == nil {
31 logger.Warningf("Connect %s: wrong address type", target)
32 return &socksproxy.ConnectResponse{
33 Error: socksproxy.ReplyAddressTypeNotSupported,
34 }
Serge Bazanskibe742842022-04-04 13:18:50 +020035 }
Lorenz Brun08fd1cb2025-02-10 19:11:17 +010036 addr = req.Address
37 } else {
38 target = net.JoinHostPort(req.Hostname, fmt.Sprintf("%d", req.Port))
39 ip, err := net.ResolveIPAddr("ip", req.Hostname)
40 if err != nil {
41 logger.Warningf("Connect %s: while resolving hostname: %v", target, err)
42 return &socksproxy.ConnectResponse{
43 Error: socksproxy.ReplyAddressTypeNotSupported,
44 }
45 }
46 addr = ip.IP
Serge Bazanskibe742842022-04-04 13:18:50 +020047 }
48
Serge Bazanskibe742842022-04-04 13:18:50 +020049 switchCIDR := net.IPNet{
50 IP: switchIP.Mask(switchSubnetMask),
51 Mask: switchSubnetMask,
52 }
53 if !switchCIDR.Contains(addr) || switchCIDR.IP.Equal(addr) {
54 logger.Warningf("Connect %s: not in switch network", target)
55 return &socksproxy.ConnectResponse{
56 Error: socksproxy.ReplyNetworkUnreachable,
57 }
58 }
59
60 con, err := net.Dial("tcp", target)
61 if err != nil {
62 logger.Warningf("Connect %s: dial failed: %v", target, err)
63 return &socksproxy.ConnectResponse{
64 Error: socksproxy.ReplyHostUnreachable,
65 }
66 }
67 res, err := socksproxy.ConnectResponseFromConn(con)
68 if err != nil {
69 logger.Warningf("Connect %s: could not make SOCKS response: %v", target, err)
Serge Bazanski1ec1fe92023-03-22 18:29:28 +010070 con.Close()
Serge Bazanskibe742842022-04-04 13:18:50 +020071 return &socksproxy.ConnectResponse{
72 Error: socksproxy.ReplyGeneralFailure,
73 }
74 }
75 logger.Infof("Connect %s: established", target)
76 return res
77}
78
79// runSOCKSProxy starts a SOCKS proxy to the nanoswitchnetwork at SOCKSPort.
80func runSOCKSProxy(ctx context.Context) error {
81 lis, err := net.Listen("tcp", fmt.Sprintf(":%d", SOCKSPort))
82 if err != nil {
Tim Windelschmidtadcf5d72024-05-21 13:46:25 +020083 return fmt.Errorf("failed to listen on :%d : %w", SOCKSPort, err)
Serge Bazanskibe742842022-04-04 13:18:50 +020084 }
85
86 h := &socksHandler{}
87 supervisor.Signal(ctx, supervisor.SignalHealthy)
88 return socksproxy.Serve(ctx, h, lis)
89}