Scan commands --------------------------------------------------------
()
| 249 | // Scan commands -------------------------------------------------------- |
| 250 | |
| 251 | func (m *scanModel) startSNI() tea.Cmd { |
| 252 | tgt, err := netip.ParseAddr(strings.TrimSpace(m.target.Value())) |
| 253 | if err != nil { |
| 254 | return setStatus("invalid target: %v", err) |
| 255 | } |
| 256 | m.reset() |
| 257 | m.running = true |
| 258 | m.mode = scanModeSNI |
| 259 | m.started = time.Now() |
| 260 | m.snis = nil |
| 261 | m.sniDone = 0 |
| 262 | m.sniTotal = len(scanner.DefaultSNICandidates) |
| 263 | |
| 264 | ctx, cancel := context.WithCancel(context.Background()) |
| 265 | m.cancel = cancel |
| 266 | return func() tea.Msg { |
| 267 | results := scanner.ProbeSNIs(ctx, scanner.DefaultSNICandidates, scanner.ProbeConfig{ |
| 268 | TargetIP: tgt, |
| 269 | TargetPort: 443, |
| 270 | ConnectTimeout: 4 * time.Second, |
| 271 | HandshakeTimeout: 4 * time.Second, |
| 272 | Concurrency: 16, |
| 273 | }, nil) |
| 274 | // Push results in one chunk after completion. (For truly per-probe |
| 275 | // streaming in Bubble Tea we'd need a channel-backed cmd; batch is |
| 276 | // fine for now and keeps the code small.) |
| 277 | cmds := make([]tea.Cmd, 0, len(results)+1) |
| 278 | for _, r := range results { |
| 279 | r := r |
| 280 | cmds = append(cmds, func() tea.Msg { return sniResultMsg(r) }) |
| 281 | } |
| 282 | cmds = append(cmds, func() tea.Msg { return scanDoneMsg{} }) |
| 283 | return tea.Sequence(cmds...)() |
| 284 | } |
| 285 | } |
| 286 | |
| 287 | func (m *scanModel) startIP() tea.Cmd { |
| 288 | m.reset() |