116 lines
3 KiB
Markdown
116 lines
3 KiB
Markdown
# hss_parse_services / hss_parse_config
|
||
|
||
**Source:** `hss-ports.h:39` and `hss-ports.h:58`
|
||
|
||
Builds the candidate port list from `/etc/services` and the user's
|
||
`~/.config/.hssrc` config file.
|
||
|
||
## hss_parse_services
|
||
|
||
```c
|
||
static void hss_parse_services(struct hss_port_entry *e, int *n);
|
||
```
|
||
|
||
Reads `/etc/services`, the system-wide service database, and adds
|
||
matching ports to the list via `hss_add_entry`.
|
||
|
||
### Parsing
|
||
|
||
```c
|
||
FILE *f = fopen("/etc/services", "r");
|
||
while (fgets(line, sizeof(line), f)) {
|
||
if (line[0] == '#' || line[0] == '\n') continue;
|
||
end = -1;
|
||
if (sscanf(line, "%63s %d-%d/%15s", name, &start, &end, proto) < 4 &&
|
||
scanf(line, "%63s %d/%15s", name, &start, proto) != 3) continue;
|
||
```
|
||
|
||
- Skip comments and blank lines.
|
||
- Accept two formats: `name start-end/proto` (range) and
|
||
`name start/proto` (single port).
|
||
- If the first `sscanf` matches fewer than 4 fields, try the single-port
|
||
form. If neither matches, skip the line.
|
||
|
||
### Range handling
|
||
|
||
```c
|
||
if (end < 0) end = start;
|
||
if (end - start + 1 > 20) end = start + 19;
|
||
for (int p = start; p <= end; p++)
|
||
if (p > 0 && p < 65536 && hss_is_common_port(p))
|
||
hss_add_entry(e, n, p, name);
|
||
```
|
||
|
||
- If the entry was a single port, `end == start`.
|
||
- Ranges longer than 20 ports are capped (`start + 19`) to avoid adding
|
||
huge blocks of ephemeral ports.
|
||
- Only ports passing `hss_is_common_port()` are added — that function
|
||
(`hss-ports.h:20`) accepts ports 1–1023 and the curated modern-port
|
||
list (8080, 8443, 3000, 5000, etc.).
|
||
|
||
### IPv6 skip
|
||
|
||
```c
|
||
if (strstr(proto, "6")) continue;
|
||
```
|
||
|
||
Entries whose protocol contains `"6"` (e.g., `tcp6`) are skipped. The
|
||
tool only probes IPv4 (`AF_INET`) because `hss_get_eth_ips` enumerates
|
||
IPv4 addresses only.
|
||
|
||
## hss_parse_config
|
||
|
||
```c
|
||
static void hss_parse_config(const char *path, struct hss_port_entry *e, int *n);
|
||
```
|
||
|
||
Reads a user config file (default: `~/.config/.hssrc`) and adds ports.
|
||
|
||
### Path expansion
|
||
|
||
```c
|
||
if (path[0] == '~') {
|
||
if (!getenv("HOME")) return;
|
||
snprintf(expanded, sizeof(expanded), "%s%s", getenv("HOME"), path + 1);
|
||
path = expanded;
|
||
}
|
||
```
|
||
|
||
If the path starts with `~`, expand it using `$HOME`. If `HOME` is
|
||
unset, skip silently.
|
||
|
||
### Parsing
|
||
|
||
```c
|
||
while (fgets(line, sizeof(line), f)) {
|
||
if (line[0] == '#' || line[0] == '\n') continue;
|
||
int port = atoi(line);
|
||
if (port > 0 && port < 65536) hss_add_entry(e, n, port, NULL);
|
||
}
|
||
```
|
||
|
||
- Skip comments and blank lines.
|
||
- Convert each line to an integer with `atoi`.
|
||
- Valid ports (1–65535) are added with `NULL` name (displayed as the
|
||
port number).
|
||
|
||
The config file is line-based — one port per line:
|
||
|
||
```
|
||
# extra ports to scan
|
||
9090
|
||
5432
|
||
3306
|
||
```
|
||
|
||
## Call order
|
||
|
||
In `hss.c`, the sources are loaded in priority order:
|
||
|
||
1. `hss_parse_services` — system-wide common ports.
|
||
2. Built-in modern-port list (`hss_modern_ports`) — hardcoded in
|
||
`hss-ports.h:11`.
|
||
3. `hss_parse_config` — user overrides.
|
||
|
||
Because `hss_add_entry` deduplicates, the same port appearing in
|
||
multiple sources is only probed once.
|