Find DHCP server with nmap

2019-09-04

TL;DR

Unknown DHCP Server in your network? sudo nmap --script broadcast-dhcp-discover

Story time

You enter the office like every morning, go upstairs and suddenly 3 Sales-colleges shout at you - the Internet is down.

You sit down next to one of their PCs and start debugging.
You see the PC got an IP address - 192.168.88.54.
Wait a second - our router is configured for the network 192.168.0.0/24!
What's going on here?
You start your own PC - same thing.

First of all, you set static IP addresses for the correct network on all PCs - they can reach the outside world again, and your co-workers can continue working.

Next step: You need to find out where the .88.*-IPs come from.

Thankfully, there is a nice nmap script for that:

$ sudo nmap --script broadcast-dhcp-discover

Pre-scan script results:
| broadcast-dhcp-discover:
|   Response 1 of 1:
|     IP Offered: 192.168.88.133
|     DHCP Message Type: DHCPOFFER
|     Server Identifier: 192.168.0.208
|     IP Address Lease Time: 10m00s
|     Subnet Mask: 255.255.255.0
|     Router: 192.168.88.1

Service Info: Host: the_office; OSs: Linux, RouterOS; Device: router; CPE: cpe:/o:mikrotik:routeros, cpe:/o:linux:linux_kernel

"We don't have any MikroTik products in our office", you think.

You do an image search for MikroTik routers on your phone and wander around in the office to find a similar-looking small box.

Half an hour later, you find it under someones desk, burried between ethernet cables. You remove it from the network and voila, everyone gets IP addresses from the correct DHCP server again.

Later you find out, that one of your co-workers wanted to add a switch to the network to expand the available ethernet ports. In a misunderstanding, they added a router instead.

Thanks to you (and this handy script), the internet is saved and you can finally start your working day.


Specify docker exec user

2019-09-03

With docker exec, you can execute commands inside of running Docker containers. The --user flag allows you to declare the user to use inside the container.

Example:

$ docker run -d
cf4bea1aa03eafc0a4adf49cc1f38e98de66ab586cbf026d369de2d51f83fbc3
$ docker exec -it --user postgres cf4bea1a /bin/bash
[email protected]:/$

Postgres Constraint Naming Convention

2019-09-02

Sometimes it's necessary to manually specify a constraint name, which should then ideally follow some sort of naming convention or pattern.

Postgres already has an implicit naming convention in place, which goes like this:

{tablename}_{columnname(s)}_{suffix}
  • pkey for primary key constraints

    • Single column

      create table foo (
        bar integer primary key
      );
                                  Table "public.foo"
       Column |  Type   | Collation | Nullable |             Default
      --------+---------+-----------+----------+---------------------------------
       bar    | integer |           | not null |
      Indexes:
          "foo_pkey" PRIMARY KEY, btree (bar)
    • Multiple columns

      create table foo (
        bar integer,
        baz integer,
        primary key (bar, bar)
      );
                      Table "public.foo"
       Column |  Type   | Collation | Nullable | Default
      --------+---------+-----------+----------+---------
       bar    | integer |           | not null |
       baz    | integer |           | not null |
      Indexes:
          "foo_pkey" PRIMARY KEY, btree (bar, baz)
  • key for unique constraints

    • Single column

      create table foo (
        bar integer unique
      );
                  Table "public.foo"
       Column |  Type   | Collation | Nullable | Default
      --------+---------+-----------+----------+---------
       bar    | integer |           |          |
      Indexes:
        "foo_bar_key" UNIQUE CONSTRAINT, btree (bar)
    • Multiple columns

      create table foo (
        bar integer,
        baz integer,
        unique (bar, baz)
      );
                      Table "public.foo"
       Column |  Type   | Collation | Nullable | Default
      --------+---------+-----------+----------+---------
       bar    | integer |           |          |
       baz    | integer |           |          |
      Indexes:
          "foo_bar_baz_key" UNIQUE CONSTRAINT, btree (bar, baz)
  • excl for exclusion constraints

    create table foo (
      bar text,
      baz text,
      exclude using gist (bar with =, baz with =)
    );
                 Table "public.foo"
     Column | Type | Collation | Nullable | Default
    --------+------+-----------+----------+---------
     bar    | text |           |          |
     baz    | text |           |          |
    Indexes:
        "foo_bar_baz_excl" EXCLUDE USING gist (bar WITH =, baz WITH =)
  • idx for indices

    Indices can not be created without manually specifying a name.

  • fkey for foreign key constraints

    • Single column

      create table foo (
        bar integer primary key
      );
      create table qux (
        bar integer references foo
      );
                      Table "public.qux"
       Column |  Type   | Collation | Nullable | Default
      --------+---------+-----------+----------+---------
       bar    | integer |           |          |
      Foreign-key constraints:
          "qux_bar_fkey" FOREIGN KEY (bar) REFERENCES foo(bar)
    • Multiple columns

      create table foo (
        bar integer,
        baz integer,
        primary key(bar, baz)
      );
      create table qux (
        bar integer,
        baz integer,
        foreign key(bar, baz) references foo (bar, baz)
      );
                      Table "public.qux"
       Column |  Type   | Collation | Nullable | Default
      --------+---------+-----------+----------+---------
       bar    | integer |           |          |
       baz    | integer |           |          |
      Foreign-key constraints:
          "qux_bar_fkey" FOREIGN KEY (bar, baz) REFERENCES foo(bar, baz)
  • check for check constraints

    • Single column

      create table foo (
        bar integer check (id > 10)
      );
                      Table "public.foo"
       Column |  Type   | Collation | Nullable | Default
      --------+---------+-----------+----------+---------
       bar    | integer |           |          |
      Check constraints:
          "foo_bar_check" CHECK (id > 10)
    • Multiple columns

      create table foo (
        bar integer,
        baz integer,
        check (bar = baz)
      );
                      Table "public.foo"
       Column |  Type   | Collation | Nullable | Default
      --------+---------+-----------+----------+---------
       bar    | integer |           |          |
       baz    | integer |           |          |
      Check constraints:
          "foo_check" CHECK (bar = baz)
  • seq for sequences

    create table foo (
      id serial
    );
                                Table "public.foo"
    Column |  Type   | Collation | Nullable |             Default
    --------+---------+-----------+----------+---------------------------------
     id     | integer |           | not null | nextval('foo_id_seq'::regclass)

Disable pager for psql

2019-09-01

PostgreSQL's CLI psql offers a myriad of helpful features.

For example, psql detects whenever a large result-set is returned and uses a pager to display the content.

While this is great for viewing your data, it is really inconvenient for automating tasks, as the pager needs user input to be terminated.
So, how can we circumvent / deactivate the pager?

# original, shows the pager
psql -h localhost -U postgres -c "SELECT * FROM pg_class"

# just pipe the output to `cat`
psql -h localhost -U postgres -c "SELECT * FROM pg_class" | cat

# if you are not interested in the output, you can also write to /dev/null
psql -h localhost -U postgres -c "SELECT * FROM pg_class" > /dev/null

# alternatively, you can use the environment variable `PAGER` to choose which pager should be used
PAGER=cat psql -h localhost -U postgres -c "SELECT * FROM pg_class"

# best method: completely turn off the pager
psql -h localhost -U postgres -P pager=off -c "SELECT * FROM pg_class"

Additionally, if you want to disable the pager while in interactive mode, just type \pset pager off.


Typescript ReturnType

2019-08-31

Typescript includes several useful utility types to enhance the type declarations of your code-base.

The ReturnType function is one of my favorite ones, as it helps reduce type definition duplication.

Suppose you have the following function definition:

type IsInText = (
  text: string
) => (
  term: string,
  minCount: number,
  maxCount?: number,
  caseSensitive?: boolean
) => boolean

Now we want to write a function allTermsInText, that takes the function returned by isInText as an argument. It should be used like:

allTermsInText(["Typescript", "awesome"], isInText("Typescript is awesome!"))

Here is the definition without the utility type:

type AllTermsInText = (
  terms: string[],
  search: (
    term: string,
    minCount: number,
    maxCount?: number,
    caseSensitive?: boolean
  ) => boolean
) => boolean

And here the same function definition, but using ReturnType for the parameters:

let AllTermsInText = (terms: string[], search: ReturnType<IsInText>) => {
  return !terms.find(term => !search(term, 1))
}

Pretty Printing JSON

2019-08-30

JSON is everywhere, but reading nested JSON without proper formatting can be a nightmare.

PostgreSQL

The function jsonb_pretty allows you to pretty print jsonb data.

\pset format unaligned
SELECT jsonb_pretty('{"name": "Lorenz", "team": {"name": "Team #1", "color", "blue"}}'::jsonb);

{
    "name": "Lorenz",
    "team": {
        "name": "Team #1",
        "color": "blue"
    }
}

Javascript

If you work with JSON data in Javascript, you surely know the function JSON.stringify. But did you know it can prettify your JSON as well?

JSON.stringify({"name": "Lorenz", "games_won": 4, "games_lost": 1}, null, 4)
                                      // number of spaces for indentation ^

{
    "name": "Lorenz",
    "games_won": 4,
    "games_lost": 1
}

Python

Python's json module adds functions to work with JSON.

>>> import json
>>> print(json.dumps({"players": [{"name": "Lorenz"}, {"name": "Philip"}]}, indent=4))

{
    "players": [
        {
            "name": "Lorenz"
        },
        {
            "name": "Philip"
        }
    ]
}

Command line using Python

You can also directly run the tool exposed by the json module from the command line:

$ echo '{"name": "Lorenz", "has_eyes": true}' | python3 -m json.tool

{
    "name": "Lorenz",
    "has_eyes": true
}

Delete already merged branches

2019-08-28

The code example below shows how to delete all branches which have already been merged into the current branch:

$ git branch
  feature-1
  feature-2
  feature-3
* master

$ git branch --merged
  feature-1
* master

$ git branch --merged | egrep -v "(^\*|master)"
  feature-1

$ git branch --merged | egrep -v "(^\*|master)" | xargs git branch -d
Deleted branch feature-1 (was 1d7fd54).

Check out this great Stack Overflow answer for more information.