| 131 | |
| 132 | |
| 133 | class Socks5Proxy(DestinationKnown): |
| 134 | buf: bytes = b"" |
| 135 | |
| 136 | def socks_err( |
| 137 | self, |
| 138 | message: str, |
| 139 | reply_code: int | None = None, |
| 140 | ) -> layer.CommandGenerator[None]: |
| 141 | if reply_code is not None: |
| 142 | yield commands.SendData( |
| 143 | self.context.client, |
| 144 | bytes([SOCKS5_VERSION, reply_code]) |
| 145 | + b"\x00\x01\x00\x00\x00\x00\x00\x00", |
| 146 | ) |
| 147 | yield commands.CloseConnection(self.context.client) |
| 148 | yield commands.Log(message) |
| 149 | self._handle_event = self.done |
| 150 | |
| 151 | @expect(events.Start, events.DataReceived, events.ConnectionClosed) |
| 152 | def _handle_event(self, event: events.Event) -> layer.CommandGenerator[None]: |
| 153 | if isinstance(event, events.Start): |
| 154 | pass |
| 155 | elif isinstance(event, events.DataReceived): |
| 156 | self.buf += event.data |
| 157 | yield from self.state() |
| 158 | elif isinstance(event, events.ConnectionClosed): |
| 159 | if self.buf: |
| 160 | yield commands.Log( |
| 161 | f"Client closed connection before completing SOCKS5 handshake: {self.buf!r}" |
| 162 | ) |
| 163 | yield commands.CloseConnection(event.connection) |
| 164 | else: |
| 165 | raise AssertionError(f"Unknown event: {event}") |
| 166 | |
| 167 | def state_greet(self) -> layer.CommandGenerator[None]: |
| 168 | if len(self.buf) < 2: |
| 169 | return |
| 170 | |
| 171 | if self.buf[0] != SOCKS5_VERSION: |
| 172 | if self.buf[:3].isupper(): |
| 173 | guess = "Probably not a SOCKS request but a regular HTTP request. " |
| 174 | else: |
| 175 | guess = "" |
| 176 | yield from self.socks_err( |
| 177 | guess + "Invalid SOCKS version. Expected 0x05, got 0x%x" % self.buf[0] |
| 178 | ) |
| 179 | return |
| 180 | |
| 181 | n_methods = self.buf[1] |
| 182 | if len(self.buf) < 2 + n_methods: |
| 183 | return |
| 184 | |
| 185 | if "proxyauth" in self.context.options and self.context.options.proxyauth: |
| 186 | method = SOCKS5_METHOD_USER_PASSWORD_AUTHENTICATION |
| 187 | self.state = self.state_auth |
| 188 | else: |
| 189 | method = SOCKS5_METHOD_NO_AUTHENTICATION_REQUIRED |
| 190 | self.state = self.state_connect |
no outgoing calls
searching dependent graphs…