# ripcalc

Calculate or lookup network addresses.

# install

```
$ git clone 'https://gitlab.com/edneville/ripcalc.git'
$ cd ripcalc \
  && cargo build --release \
  && please install -m 0755 -s target/release/ripcalc /usr/local/bin
```

or

```
please snap install ripcalc
```

# usage

Ripcalc allows networks to be provided by argument

```
$ ripcalc 127.0.0.1/8
IP is: 127.0.0.1/8
Broadcast is: 127.255.255.255
Network is: 127.0.0.0
Subnet is: 255.0.0.0
Wildcard is: 0.255.255.255
Network size: 16777216
```

The same output is visible with stdin:

```
echo '127.0.0.1/8' | ripcalc
...
```

The output format can be customised:

```
$ ripcalc 2001:ba8:1f1:f1cb::4/64 --format "select * from IP6 where (ip >= %ln and ip <= %lb) and active = 1;\nupdate IP6 set active = 0 where (ip >= %ln and ip <= %lb) and active = 1;"
select * from IP6 where (ip >= 42540724579414763292693624807812497408 and ip <= 42540724579414763311140368881522049023) and active = 1;
update IP6 set active = 0 where (ip >= 42540724579414763292693624807812497408 and ip <= 42540724579414763311140368881522049023) and active = 1;
```

# pipes

Sometimes if you want to quickly see if an address is part of a group of networks you can set something like this in your `.bash_aliases`:

```
alias is_our_networks='ripcalc --inside 192.168.0.0/16 --format short'
```

With this alias it would then be possible to do something like this to quickly see if the domain uses your infrastructure:

```
dig +short domain.com | is_our_networks
```

# formatting

*%* denotes a format control character, followed by one of the following:

| placeholder | effect |
|-------------|--------|
| %a          | IP address string |
| %n          | Network address string |
| %s          | Subnet address string |
| %w          | Wildcard address string |
| %b          | Broadcast address string |

Additional characters prefixing the above placeholder can control the representation:

| placeholder | effect |
|-------------|--------|
| %B          | Binary address string |
| %S          | Split binary at network boundary string |
| %l          | Unsigned integer string |
| %L          | Signed integer string |
| %x          | Hex address string |

Other format characters:

| placeholder | effect |
|-------------|--------|
| %c          | CIDR mask |
| %C          | In encapsulated context, used address count |
| %t          | Network size |
| %r          | Network reservation information (if available) |
| %d          | Matching device interface by IP |
| %m          | Matching media link interface by network |
| %p          | PTR record |
| %k          | RBL/reverse DNS-style format |
| %D          | Network size (--networks) |
| %N          | Number of subnets (--networks) |
| %%          | % |
| \n          | Line break |
| \t          | Tab character |

For example:

```
$ ripcalc --format '%k.all.s5h.net\n' 192.168.1.2
2.1.168.192.all.s5h.net
```


With a csv it can find networks that an IP address is within, use `%{field}` to print matches:

```
$ cat nets.csv
network,range,owner
rfc1918,192.168.0.0/16,bob
rfc1918,172.16.0.0/12,cliff
rfc1918,10.0.0.0/8,mr nobody
$ ripcalc --csv nets.csv -i range --format '%{owner}\n' 192.168.0.0
bob
```

Addresses can be read via file or from stdin (-):

```
$ cat list
127.0.0.1/28
10.0.0.1/28
192.168.1.1/30
172.18.1.1/30
10.0.0.0/30
$ ripcalc --csv nets.csv -i range --format '%{range} %{owner}\n' -s list
10.0.0.0/8 mr nobody
192.168.0.0/16 bob
172.16.0.0/12 cliff
10.0.0.0/8 mr nobody
```

When `-a` is used, addresses read from `-s` will not be shown when listing `-l` a network, showing only available addresses.

When `-e` is used with `-s` the smallest encapsulating network will be returned.

Given a list of IP addresses, print only those that match the network. When `s` and `inside` are used, only addresses from `-s` are printed if they are that are inside of the IP source network on the command line. This can be inverted with `--outside:

```
$ echo -e '192.168.0.0\n192.167.255.255\n' | ripcalc -s - --inside 192.168.0.0/16 --format short
192.168.0.0
$ echo -e '192.168.0.0\n192.167.255.255\n' | ripcalc -s - --outside 192.168.0.0/16 --format short
192.167.255.255
```

IP addresses can be treated as reversed, if `/proc/net/route` holds addresses in reversed format, `--reverse inputs` and `--base 16` could be used together to convert to dotted-quad.

# integer inputs

To process addresses in signed integer form, use `--base -10` which will do the conversion.

To quickly format human-readable IP addresses to a database that stores addresses as integers, assuming addreses are in a table called IP4 and are signed integers:

```
printf '10.0.0.0/8\n192.168.0.0/16\n172.16.0.0/12\n127.0.0.0/8\n1.0.0.0/8\n' \
| ripcalc --format 'select ip from IP4 where active = 1 and (ip > %Ln and ip < %Lb);\n' \
| mysql -urip -pcalc ipdata \
| ripcalc -q --base 10 --format short
```

# within networks

Is a domain wihtin a list of subnets? For example, in this part of the globe cloudflare.com was being served from their published list of networks:

```
echo http://cloudflare.com | ripcalc --inside 173.245.48.0/20 103.21.244.0/22 \
    103.22.200.0/22 103.31.4.0/22 141.101.64.0/18 108.162.192.0/18 \
    190.93.240.0/20 188.114.96.0/20 197.234.240.0/22 198.41.128.0/17 \
    162.158.0.0/15 104.16.0.0/13 104.24.0.0/14 172.64.0.0/13 \
    131.0.72.0/22 --format short
104.16.133.229
```

How many addresses is all that in total?

```
ripcalc 173.245.48.0/20 103.21.244.0/22 103.22.200.0/22 103.31.4.0/22 \
    141.101.64.0/18 108.162.192.0/18 190.93.240.0/20 188.114.96.0/20 \
    197.234.240.0/22 198.41.128.0/17 162.158.0.0/15 104.16.0.0/13 \
    104.24.0.0/14 172.64.0.0/13 131.0.72.0/22 --format '%t\n' \
    | paste -sd+ \
    | bc -l
1524736
```

If you need to manage a lot of IP addresses this could be helpful to you.

# divide

Networks can be divided into subnets:

```
$ ripcalc 192.168.1.10/24 --divide 26 --format cidr
192.168.1.0/26
192.168.1.64/26
192.168.1.128/26
192.168.1.192/26
```

# quickly block the encapsulating network

Suppose a large flood of requests are from a network pattern, to preserve service you may want to block the whole network that encapsulates a list:

```
please ip route add blackhole `ripcalc -e 192.168.56.10 192.168.57.1 192.168.44.47`
```

Networks can be grouped, in a scenario where you have a list of unwanted traffic, you can turn this into a list of small networks to block, supposing you don't want to block anything that covers more than a /19:

```
cat bad_traffic | ripcalc --encapsulating --group 19 --format cidr
```

This might be of help to you, assuming you can select a chunk of bad traffic via a `grep`:

```
grep -h scams log/* | awk '{print $1}' | ripcalc --encapsulating --group 24 --format '%C %a/%c\n'
15 192.168.1.0/25
12 172.16.80.0/24
1 172.16.209.9/32
```

Grouping with a limit helps show spread, without expanding beyond sensible limits. Setting a very large `group` mask would of course return very large results, using a smaller `group` can limit this so the probability of including legitimate traffic is reduced dramatically.

IP address counts can be shown with `countseen` and `group`:

```
cat log | ripcalc --countseen --quiet --format '%C %a/%c\n'
```

# cdb

CDB databases are fast and if you have a large list of networks they offer a good way to lookup addresses without parsing CSV. CDB lookups can be performed using IP/cidr keys and the returned values should be stored as a NULL joined key=value string, e.g.:

```
192.168.1.0/24 name=lan\0owner=build\0service=web
```

The `--makethymecdb` argument will download ASN information from thyme.apnic.net and build that into a `cdb` file, or you can make your own. I find the data from thyme perfect for my needs, but this is the internet and geo-IP, please don't rely on geo-IP being accurate.

Obviously, if you have a fleet of computers using this data, it is best to download and build in one location then fan it out using `rsync` to your other computers to save resources and processing power.

Files can also be made using `--makecdb`, the stdin should be in the format of:

```
2600:3c0f:25::/48,ASNDESC=AKAMAI-LINODE-AP Akamai Connected Cloud,ASNCC=SG,ASN=2600:3c0f:25::/48,NET=63949
```

See cdb_maker.pl for a helper script which builds this. An example for making these can be seen in the Makefile in the ipdb target, it download ASN data and builds that using cdb_maker.pl, and this can be used like this:

```
ripcalc --cdb ipdb.cdb --format '%{ASNDESC} %{ASNCC} %a/%c\n' 1.1.1.1
CLOUDFLARENET US 1.1.1.1/24
```

# filter

Input can be filtered using `--filter` which can be helpful as an accompaniment for `grep`-like workflows.

```
cat /var/log/apache/access.log | ripcalc --filter 1.2.3.0/24
```

Or inverted with `--outside`.

```
cat /var/log/apache/access.log | ripcalc --filter 1.1.1.0/24 --outside
```

`--filter` will use the first word in the inputline and try to parse that for an IP address, if the IP address is not the first word in the input, then `--filternum` can be used to indicate which word number holds the IP.

If you'd like to see the country code that the requests in your log are from:

```
cat /var/log/apache/access.log | ripcalc --filter --outside --cdb ipdb.cdb --format '%{ASNCC} %{line}\n'
```

# abuseipdb

If `--abuseipdb [key]` is used then a successful lookup will populate `%{abuseipdb_var}` (where `var` is the lookup result data field) for use in a `--format` string.

Replace `[key]` with your abuseipdb API key.

If only the country code or ISP is needed, then using a locally generated `cdb` is more efficient, see the CDB section above as that can be much faster if you don't require an external abuse score.

# maxmind geolite

MaxMind's geolite database files can be read using `--mmasn`, `--mmcountry` and `--mmcity` options. The text language can be defined with `--mmlang`.

In normal context the following are returned:

mmcity: %{mmcity_city}, %{mmcity_continent}, %{mmcity_country}, %{mmcity_code}, %{mmcity_latitude}, %{mmcity_longitude}

mmcountry: %{mmcountry_continent}, %{mmcountry_country}, %{mmcountry_registered_country}

mmasn: %{mmasn_autonomous_system_number}, %{mmasn_autonomous_system_organization
}

Less information is returned in `--top` context:

```
ripcalc --top --allowemptyrow \
    --mmcity GeoLite2-City.mmdb \
    --mmcountry GeoLite2-Country.mmdb \
    --mmasn GeoLite2-ASN.mmdb 
```

Without needing to add a `--format` string, in `--top` context, this will display `%{mmcity_code}` and `%{mmcity_country}` for `--mmcity`, `%{mmasn_autonomous_system_organization}` for `--mmasn`, and `%{mmcountry_registered_country}` for `--mmcountry`.

# top

Basic report of IP frequency, as read from `stdin`. Can be used with `--group`, `--group[46]`, `--filter`, `--filterany`, `--filternum` or `--inside` to show which networks appear most frequently.

```
ripcalc --allowemptyrow --top --inside 10.0.0.0/8 --group 24 --delay 1

                                                   10.12.0.0/14 4800 ##
                                                   10.16.0.0/14 4075 ##
                                                    10.8.0.0/14 3740 #
                                                    10.4.0.0/14 3200 #
                                                    10.0.0.0/14 2400 #
                                                   10.20.0.0/14  800 

```

A cdb IP database can be used in conjunction, which defaults to `%{ASNCC} %{ASNDESC}`:

```
ripcalc --top --inside 10.0.0.0/8 --group 14 --delay 1 --allowemptyrow --cdb ipdb.cdb
XX PRIVATE                                          10.8.0.0/14 3200 ##
XX PRIVATE                                          10.4.0.0/14 3200 ##
XX PRIVATE                                         10.12.0.0/14 3200 ##
XX PRIVATE                                         10.16.0.0/14 3200 ##
XX PRIVATE                                          10.0.0.0/14 2400 #
XX PRIVATE                                         10.20.0.0/14  800 
```

If you want to show the abuse score from AbuseIPDB at the same time you can use a format string or allow the default to be used which shows the abuse score.

`--iterations [num]` can set the number of display iterations. If you wish to run a number of displays for an email report, use with `--noclear`:

```
( printf 'To: you\nFrom: me\nSubject: IP report\n\n';
tail -Fq /var/log/apache2/*log
| ripcalc --top --cdb ipdb.cdb --group4 24 --group6 64 --allowemptyrow --iterations 3 --noclear )
| /usr/sbin/sendmail -fme@example you@example
```

# help

```
ripcalc version 0.2.7

Options:
    -4, --ipv4          treat inputs as ipv4 address
    -6, --ipv6          treat inputs as ipv6 address
    -a, --available     display unused addresses
        --abuseipdb KEY abuseipdb API
        --allowemptyrow 
                        when no matching cdb/csv network, use empty fields
    -b, --base INTEGER  ipv4 base format, default to oct
        --cdb PATH      cdb reference file
        --countseen     count times an ip is seen
    -c, --csv PATH      csv reference file
    -d, --divide CIDR   divide network into chunks
        --noexpand      do not expand networks in list
    -e, --encapsulating 
                        display encapsulating network from arguments or lookup
                        list
    -f, --format STRING format output
                        'cidr' expands to %a/%c\n
                        'short' expands to %a\n
                        See manual for more options
        --filter        print STDIN line if field parses as an IP and matches,
                        defaults to 1, use filternum to adjust
        --filterany     print STDIN line if any IP on STDIN matches
        --filternum NUMBER
                        change position NUMBER for IP filter, enables --filter
        --group CIDR    maximum network group size for encapsulation
        --group4 CIDR   v4 specific group, overrides group in top mode
        --group6 CIDR   v6 specific group, overrides group in top mode
    -h, --help          display help
    -i, --field FIELD   csv/db/json field
    -l, --list          list all addresses in network
        --outside       display when extremities are outside network
        --inside        display when extremities are inside network
        --makecdb PATH  build a cdb file from STDIN
        --makethymecdb PATH
                        download and build a cdb file, defaults to
                        thyme.apnic.net data
        --data-raw-table URL or PATH
                        URL/path of raw data
        --ipv6-raw-table URL or PATH
                        URL/path of ipv6 data
        --data-used-autnums URL or PATH
                        URL/path of ASN data
        --top           show IP frequency like top
        --delay SECONDS top update delay in seconds
        --iterations NUMBER
                        top iterations
        --noclear       don't print clear screen codes
        --mmlang LANG   the lang to use in results, defaults to en
        --mmasn PATH    path to maxmind geoip asn file
        --mmcity PATH   path to maxmind geoip city file
        --mmcountry PATH
                        path to maxmind geoip country file
    -m, --mask CIDR     cidr mask
    -n, --networks CIDR instead of hosts, display number of subnets of this
                        size
        --json PATH     json prefix file
    -q, --quiet         don't report errors
    -r, --reverse       (none, inputs, sources or both) v4 octets, v6 hex
    -s, --file PATH     lookup addresses from, - for stdin
    -v, --version       print version
```

