Can curl make a connection to any TCP ports, not just HTTP/HTTPS?
Categories:
Beyond HTTP: Using cURL for Raw TCP Connections

Discover how cURL, often associated with HTTP/HTTPS, can establish and interact with raw TCP connections to any port, enabling versatile network testing and communication.
While cURL
is predominantly known for its robust capabilities in handling HTTP and HTTPS requests, its underlying power extends far beyond web protocols. At its core, cURL
is a command-line tool and library for transferring data with URLs, supporting a wide range of protocols. This article explores how to leverage cURL
to establish raw TCP connections to arbitrary ports, allowing you to interact with services that don't speak HTTP, such as database servers, mail servers, or custom network applications. Understanding this functionality can be incredibly useful for network diagnostics, testing, and even simple data exchange.
The --raw
and --tcp-nodelay
Flags
The key to making cURL
behave like a raw TCP client lies in specific command-line flags. The --raw
flag (or -r
) tells cURL
to send the data exactly as provided, without any protocol-specific processing like adding HTTP headers. This is crucial for interacting with non-HTTP services. Additionally, the --tcp-nodelay
flag can be useful. It disables the Nagle algorithm, which can sometimes introduce small delays by buffering small packets. For interactive or time-sensitive raw TCP communication, disabling Nagle's algorithm can improve responsiveness, though it might slightly increase network overhead.
curl --raw telnet://localhost:23
curl --raw telnet://example.com:8080
curl --raw --tcp-nodelay telnet://192.168.1.1:1234
Basic cURL commands for raw TCP connections
Sending Data Over Raw TCP
To send data over a raw TCP connection, you can combine the --raw
flag with the -d
(data) or --data-binary
flags. The -d
flag sends data as a POST request by default, but with --raw
, it simply sends the specified string. For binary data or to prevent cURL
from interpreting special characters, --data-binary
is preferred. You can also pipe input directly into cURL
using standard input (-T -
or < file
). This allows for sending multi-line commands or file contents to a TCP service.
sequenceDiagram participant User participant cURL participant TCP_Service User->>cURL: curl --raw telnet://host:port -d "Hello" cURL->>TCP_Service: Establish TCP connection cURL->>TCP_Service: Send "Hello" (raw bytes) TCP_Service-->>cURL: Response (raw bytes) cURL-->>User: Display response
Sequence diagram of cURL sending raw data over TCP
# Sending a simple string
curl --raw telnet://localhost:12345 -d "Hello, TCP server!\n"
# Sending multi-line commands from a file
cat commands.txt | curl --raw telnet://localhost:12345 -T -
# Sending binary data (e.g., a file)
curl --raw telnet://localhost:12345 --data-binary @binary_file.bin
Examples of sending data using cURL over raw TCP
--raw
, cURL
will not add any line endings or protocol-specific framing. You must include any necessary delimiters (like \n
for newlines) in your data manually, as expected by the target TCP service.Practical Use Cases and Considerations
Using cURL
for raw TCP connections opens up several practical applications:
- Network Service Testing: Quickly check if a non-HTTP service (e.g., a custom daemon, a game server, or a database listener) is responding on a specific port and exchange basic commands.
- Debugging: Send specific byte sequences to a service to debug its behavior without needing a full client application.
- Simple Data Exchange: For very basic, ad-hoc data transfer where setting up a full client is overkill.
- Firewall Testing: Verify if specific ports are open and reachable from a given machine.
Remember that cURL
will simply send and receive raw bytes. It won't interpret or format the response in any way. You'll see the raw output from the server, which might be human-readable text, binary data, or a mix. For more complex interactions or protocol parsing, dedicated client libraries or tools are usually more appropriate.
cURL
commands or use a script to manage the interaction, as cURL
itself doesn't maintain state across separate calls.