# Building a TCP Port Scanner in F#

# Introduction

One of the best ways to understand TCP networking is by building a simple port scanner.

A port scanner attempts to connect to remote TCP ports and determines whether they are available. While the implementation may be small, it exposes several important networking concepts:

- TCP connections
- Client-server communication
- TCP handshakes
- Open and closed ports
- Exception handling
- Socket programming
- F# pattern matching

This article explores how a simple F# program can test TCP port availability and introduces the exception-handling syntax commonly used in networking applications.

---

# What Is a TCP Port?

A TCP port is a logical communication endpoint.

Servers listen on ports waiting for incoming connections.

Examples:

| Service | Port |
|----------|----------|
| HTTP | 80 |
| HTTPS | 443 |
| SSH | 22 |
| SMTP | 25 |
| FTP | 21 |

When a client wants to communicate with a service, it attempts to establish a TCP connection to the target port.

---

# What Is Port Scanning?

Port scanning is the process of testing one or more ports to determine whether they are accepting connections.

A scanner typically reports:

| State | Meaning |
|---------|---------|
| Open | Service accepts connections |
| Closed | Service rejects connections |
| Filtered | Firewall blocks traffic |
| Unreachable | Host cannot be reached |

Port scanners are widely used in:

- Network administration
- Security auditing
- Asset discovery
- Troubleshooting
- Cybersecurity assessments

---

# Understanding TCP Connections

Before data can be exchanged, TCP establishes a connection between client and server.

The client sends a connection request.

The server responds.

Once both sides agree, communication begins.

If the connection succeeds, the port is considered open.

If the connection fails, the scanner can infer that the service is unavailable or inaccessible.

---

# Connecting with TcpClient

The .NET networking library provides the `TcpClient` class.

A connection can be created using:

```fsharp
use client =
    new TcpClient("scanme.nmap.org", 80)
```

This statement attempts to connect to:

- Host: `scanme.nmap.org`
- Port: `80`

If the connection succeeds, the object is created successfully.

---

# A Minimal TCP Scanner

The entire scanner can fit into a few lines of code.

```fsharp
try
    use client =
        new TcpClient("scanme.nmap.org", 80)

    printfn "Connection successful"

with
| :? SocketException ->
    printfn "Connection failed"
```

The scanner attempts a TCP connection.

Success indicates an open port.

Failure generates a networking exception.

---

# Why Error Handling Matters

Networks are unpredictable.

Many things can go wrong:

- Host offline
- Service unavailable
- Firewall blocking traffic
- DNS resolution failure
- Routing problems

Instead of crashing, the application should handle these failures gracefully.

That is where exception handling becomes important.

---

# Understanding the try Block

The `try` keyword marks code that might fail.

Example:

```fsharp
try
    connect()
```

Meaning:

```text
Attempt this operation.
If an error occurs,
handle it below.
```

Networking operations are common candidates for `try` blocks because they depend on external systems.

---

# Understanding the with Keyword

The `with` keyword begins exception handling.

Example:

```fsharp
try
    connect()

with
```

Meaning:

```text
If an exception occurs,
look for a matching handler.
```

The runtime compares the exception against each rule that follows.

---

# Understanding the Pipe Operator

The pipe symbol introduces a pattern-matching case.

Example:

```fsharp
| pattern -> action
```

Each pipe represents a possible match.

Example:

```fsharp
with
| case1 -> ...
| case2 -> ...
| case3 -> ...
```

The first matching case executes.

---

# Understanding the Type Test Operator

One of the most important operators in F# exception handling is:

```fsharp
:?
```

This performs a runtime type check.

Example:

```fsharp
:? SocketException
```

Meaning:

```text
Is this exception a SocketException?
```

If yes, the match succeeds.

If no, F# continues searching for another handler.

---

# Understanding SocketException

`SocketException` is a .NET exception used for networking errors.

Namespace:

```fsharp
System.Net.Sockets
```

Typical causes include:

| Error | Description |
|---------|---------|
| Connection Refused | Service not listening |
| Timeout | No response received |
| Host Not Found | DNS lookup failed |
| Network Unreachable | Routing issue |
| Connection Reset | Peer closed connection |

Because networking failures are common, `SocketException` appears frequently in TCP applications.

---

# Understanding the Arrow Operator

The arrow operator is:

```fsharp
->
```

It means:

```text
If this pattern matches,
execute the code on the right.
```

Example:

```fsharp
| :? SocketException ->
    printfn "Connection failed"
```

Meaning:

```text
If the exception is a SocketException,
print an error message.
```

---

# Execution Flow

Let's walk through the scanner step by step.

### Step 1

Attempt TCP connection.

```fsharp
new TcpClient(...)
```

### Step 2

Connection succeeds.

Output:

```text
Connection successful
```

or

### Step 3

Connection fails.

A `SocketException` is thrown.

### Step 4

The exception handler matches:

```fsharp
:? SocketException
```

### Step 5

The failure message is displayed.

```text
Connection failed
```

---

# Why Port Scanners Use Exceptions

Port scanners depend heavily on connection outcomes.

Successful connection:

```text
Port Open
```

Connection refused:

```text
Port Closed
```

Timeout:

```text
Port Filtered
```

Host unreachable:

```text
Target Unreachable
```

Exceptions provide a simple way to classify these outcomes.


---
# Real-World Applications

TCP scanning forms the foundation of:

- Vulnerability assessment
- Service discovery
- Asset inventory
- Penetration testing
- Network troubleshooting
- Security monitoring

Understanding how scanners work also helps administrators better understand firewall behavior and network exposure.

---

# Key Takeaways

- TCP scanners determine port availability by attempting connections.
- `TcpClient` provides a simple way to establish TCP sessions.
- Successful connections indicate open ports.
- Failed connections generate exceptions.
- `SocketException` represents common networking failures.
- `try` identifies code that may fail.
- `with` starts exception handling.
- `|` introduces pattern-matching cases.
- `:?` performs runtime type testing.
- `->` specifies the action to execute after a successful match.
- Concurrency is essential for high-performance scanning.

---

# Conclusion

Building a TCP port scanner is an excellent introduction to networking and systems programming.

Even a small scanner demonstrates several foundational concepts, including TCP connections, port states, socket programming, exception handling, and pattern matching.

For F# developers, understanding how `SocketException` integrates with pattern matching provides a clean and expressive way to handle networking failures while building reliable network applications.
````

