| 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 |
| 191 | |
| 192 | if method not in self.buf[2 : 2 + n_methods]: |
| 193 | method_str = ( |
| 194 | "user/password" |
| 195 | if method == SOCKS5_METHOD_USER_PASSWORD_AUTHENTICATION |
| 196 | else "no" |
| 197 | ) |
| 198 | yield from self.socks_err( |
| 199 | f"Client does not support SOCKS5 with {method_str} authentication.", |
| 200 | SOCKS5_METHOD_NO_ACCEPTABLE_METHODS, |
| 201 | ) |
| 202 | return |
| 203 | yield commands.SendData(self.context.client, bytes([SOCKS5_VERSION, method])) |
| 204 | self.buf = self.buf[2 + n_methods :] |
| 205 | yield from self.state() |
| 206 | |
| 207 | state: Callable[..., layer.CommandGenerator[None]] = state_greet |
| 208 | |