Skip to content

Reject listening on hostnames and document valid URIs #66

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 5, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 29 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,15 +151,40 @@ is responsible for accepting plaintext TCP/IP connections.
$server = new Server(8080, $loop);
```

By default, the server will listen on the localhost address and will not be
reachable from the outside.
You can change the host the socket is listening on through a first parameter
provided to the constructor:
As above, the `$uri` parameter can consist of only a port, in which case the
server will default to listening on the localhost address `127.0.0.1`,
which means it will not be reachable from outside of this system.

In order to use a random port assignment, you can use the port `0`:

```php
$server = new Server(0, $loop);
$port = $server->getPort();
```

In order to change the host the socket is listening on, you can provide an IP
address through the first parameter provided to the constructor, optionally
preceded by the `tcp://` scheme:

```php
$server = new Server('192.168.0.1:8080', $loop);
```

If you want to listen on an IPv6 address, you MUST enclose the host in square
brackets:

```php
$server = new Server('[::1]:8080', $loop);
```

If the given URI is invalid, does not contain a port, any other scheme or if it
contains a hostname, it will throw an `InvalidArgumentException`:

```php
// throws InvalidArgumentException due to missing port
$server = new Server('127.0.0.1', $loop);
```

Optionally, you can specify [socket context options](http://php.net/manual/en/context.socket.php)
for the underlying stream socket resource like this:

Expand Down
37 changes: 33 additions & 4 deletions src/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,40 @@ class Server extends EventEmitter implements ServerInterface
* $server = new Server(8080, $loop);
* ```
*
* By default, the server will listen on the localhost address and will not be
* reachable from the outside.
* You can change the host the socket is listening on through the first parameter
* provided to the constructor.
* As above, the `$uri` parameter can consist of only a port, in which case the
* server will default to listening on the localhost address `127.0.0.1`,
* which means it will not be reachable from outside of this system.
*
* In order to use a random port assignment, you can use the port `0`:
*
* ```php
* $server = new Server(0, $loop);
* $port = $server->getPort();
* ```
*
* In order to change the host the socket is listening on, you can provide an IP
* address through the first parameter provided to the constructor, optionally
* preceded by the `tcp://` scheme:
*
* ```php
* $server = new Server('192.168.0.1:8080', $loop);
* ```
*
* If you want to listen on an IPv6 address, you MUST enclose the host in square
* brackets:
*
* ```php
* $server = new Server('[::1]:8080', $loop);
* ```
*
* If the given URI is invalid, does not contain a port, any other scheme or if it
* contains a hostname, it will throw an `InvalidArgumentException`:
*
* ```php
* // throws InvalidArgumentException due to missing port
* $server = new Server('127.0.0.1', $loop);
* ```
*
* Optionally, you can specify [socket context options](http://php.net/manual/en/context.socket.php)
* for the underlying stream socket resource like this:
*
Expand Down Expand Up @@ -110,6 +135,10 @@ public function __construct($uri, LoopInterface $loop, array $context = array())
throw new InvalidArgumentException('Invalid URI "' . $uri . '" given');
}

if (false === filter_var(trim($parts['host'], '[]'), FILTER_VALIDATE_IP)) {
throw new \InvalidArgumentException('Given URI "' . $uri . '" does not contain a valid host IP');
}

$this->master = @stream_socket_server(
$uri,
$errno,
Expand Down
40 changes: 40 additions & 0 deletions tests/FunctionalServerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,44 @@ public function testAppliesContextOptionsToSocketStreamResource()

$this->assertEquals(array('socket' => array('backlog' => 4)), $all);
}

/**
* @expectedException InvalidArgumentException
*/
public function testFailsToListenOnInvalidUri()
{
$loop = Factory::create();

new Server('///', $loop);
}

/**
* @expectedException InvalidArgumentException
*/
public function testFailsToListenOnUriWithoutPort()
{
$loop = Factory::create();

new Server('127.0.0.1', $loop);
}

/**
* @expectedException InvalidArgumentException
*/
public function testFailsToListenOnUriWithWrongScheme()
{
$loop = Factory::create();

new Server('udp://127.0.0.1:0', $loop);
}

/**
* @expectedException InvalidArgumentException
*/
public function testFailsToListenOnUriWIthHostname()
{
$loop = Factory::create();

new Server('localhost:8080', $loop);
}
}