Networking

How to set OPKG HTTP/HTTPS proxy sever

export https_proxy=http://10.1.2.3:8080/
export http_proxy=http://10.1.2.3:8080/
opkg update

 

Posted by Uli Köhler in OpenWRT

Paid captcha solver pricing overview (September 2023)

Prices according to my own research end of september 2023. Prices may vary – check for yourself.

Note: Quoted pricing is for standard image captchas, without any high usage discounts. The recaptcha pricing varies much more

If you don’t need that many captchas, note the minimum payment!

  • deathbycaptcha.com1.39$/1k + 47% nighttime worker compensation outside their working hours, minimum payment around 7$
  • anti-captcha.com0.7$/1k, minimum payment around 11.50$, 50 free if verified via SMS
  • cheapcaptcha.com0.59$/1k, minimum payment around 7$
  • imagetyperz.com0.65$/1k, minimum payment around 10$
  • CaptchaSolutions.com  / captcha.io: Monthly pricing model starting at 22$/month for 150k captchas. This is equal to 0.146$/1k but only if you use up the entire budget within a month. Probably best suited for extreme power users.
  • EndCaptcha.com 3.99$/1k, minimum payment (starter package) around 12$

 

Posted by Uli Köhler in Networking

Where to find cheap RJ45 connectors

Generally, I always recommend going with metal-shielded RJ45 ports since those tend not to break as often.

If you want to buy more than, say, 10pcs, you can check out LCSC’s Ethernet Connectors / Modular Connectors lineup. The very good prices compensate for the shipping fee even when buying only medium quantities.

Note that it’s easy to mix up models with and without magnetics at the moment as there is no suitable filter. It’s easiest to just look at the length of the connector – RJ45 connectors without magnetics are almost cubic in size (i.e. length in the direction where you insert the connector is equal to the width) whereas connectors with magnetics are much longer. Nevertheless, always check the datasheet.

Some examples:

With magnetics:

No magnetics:

  • RCH RC01133, No LEDs, no magnetics, right angle, THT, 0.11€/pc @100pcs
  • HC-WK88-H16-DB, Two LEDs, no magnetics, right angle, THT, 0.14€/pc @ 100pcs
  • RJ45-B-1*1, Two LEDs, no magnetics, shield with case contacts, 0.22€/pc @ 100pcs
Posted by Uli Köhler in Components, Electronics, Networking

How to access RouterOS API in Python using the ‘routeros’ library (minimal example)

This example uses the routeros library from PyPI (GitHub) to access the MikroTik API and extract the system identity.

#!/usr/bin/env python3
from routeros import login

routeros = login('admin', 'abc123abc', '192.168.88.1')

output = routeros('/system/identity/print')
# Extract the one identity string from the list of dictionaries
print(output[0]['name'])

 

Posted by Uli Köhler in MikroTik, Python

Netmiko MikroTik RouterOS SSH key login example

In our previous example Netmiko MikroTik RouterOS minimal example we showed how to login to a RouterOS device using netmikoand password-based login.

#!/usr/bin/env python3  
from netmiko import ConnectHandler
import os.path
mikrotik = {
    'device_type': 'mikrotik_routeros',
    'host':   '192.168.88.1',
    'username': 'admin',
    'key_file': os.path.expanduser("~/.ssh/id_mikrotik"),
}
with ConnectHandler(**mikrotik) as mikrotik_connection:
    print(mikrotik_connection.send_command(f'/system/identity/print', cmd_verify=False))

 

Example output:

name: MySwitch01

 

Posted by Uli Köhler in MikroTik, Networking, Python

How to parse Ethernet packet header (src & dst MAC addresses) using lwIP

You can use this code, for example, in a custom packet handler function.

#include <lwip/prot/ethernet.h>

eth_hdr* hdr = reinterpret_cast<eth_hdr*>(buffer);
auto srcMAC = hdr->src.addr;
auto dstMAC = hdr->dest.addr;

Serial.printf("Received packet: Packet of length %d\n", len);
Serial.printf("    Src MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", srcMAC[0], srcMAC[1], srcMAC[2], srcMAC[3], srcMAC[4], srcMAC[5]);
Serial.printf("    Dst MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", dstMAC[0], dstMAC[1], dstMAC[2], dstMAC[3], dstMAC[4], dstMAC[5]);
Serial.printf("    Our MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", ourEthernetMAC[0], ourEthernetMAC[1], ourEthernetMAC[2], ourEthernetMAC[3], ourEthernetMAC[4], ourEthernetMAC[5]);

 

Posted by Uli Köhler in Embedded, Networking

Where does lwIP parse the Ethernet packet header?

The Ethernet packet header is parsed in ethernet_input() in lwip/src/netif/ethernet.c:

 

Posted by Uli Köhler in Embedded, Networking

What is the default esp_eth_update_input_path() handler function?

By default, esp-idf or the Arduino framework handles incoming Ethernet packets using the

static esp_err_t eth_input_to_netif(esp_eth_handle_t eth_handle, uint8_t *buffer, uint32_t length, void *priv);

function in components/esp_eth/src/esp_eth_netif_glue.c which (besides calling just calls the exported functionesp_netif_receive():

static esp_err_t eth_input_to_netif(esp_eth_handle_t eth_handle, uint8_t *buffer, uint32_t length, void *priv)
{
    return esp_netif_receive((esp_netif_t *)priv, buffer, length, NULL);
}

The function esp_netif_receive() is declared in esp_netif.h and implemented in esp_netif_lwip.c.

This function will call esp_netif->lwip_input_fn(...) on the packet, which will in turn call the interface-type specific .input_fn(...), which is one of

or for wrapped interfaces:

  • esp_netif_lwip_slip_input
  • esp_netif_lwip_ppp_input
Posted by Uli Köhler in ESP8266/ESP32, Networking

NodeJS TCP ping example (Typescript)

The following Typescript example allows you to “ping” an IP address or host name not using ICMP but using TCP connection to a given port. If the TCP connection is accepted, the ping is resolved as true. If no connection can be established, it is returned as false. In any case, no data is exchanged and the connection is closed immediately after establishing it.

import { Socket } from "net";

/**
 * Basic TCP ping that returns true if the connection is successful, false if it fails
 * The socket is closed after the connection attempt, no data is exchanged.
 */
export function TCPConnectPing(ipAddress, timeout=5000, port=80): Promise<boolean> {
    return new Promise((resolve) => {
      const socket = new Socket();
      let connected = false;
  
      // Set a timeout for the connection attempt
      const timer = setTimeout(() => {
        if (!connected) {
          socket.destroy();
          resolve(false); // Connection timed out
        }
      }, timeout);
  
      socket.connect(port, ipAddress, () => {
        clearTimeout(timer);
        connected = true;
        socket.destroy();
        resolve(true); // Connection successful
      });
  
      socket.on('error', (error) => {
        clearTimeout(timer);
        if (!connected) {
          resolve(false); // Connection failed due to error
        }
      });
    });
  }

 

Posted by Uli Köhler in Networking, NodeJS

VirtualHere USB server & systemd autostart on x86_64 in 25 seconds

The following script will download the VirtualHere USB server for the x86_64 called vhusbd.service.

#!/bin/bash
# This script installs and enables/starts the VirtualHere USB server
wget -O /usr/bin/vhusbd https://www.virtualhere.com/sites/default/files/usbserver/vhusbdx86_64
chmod a+x /usr/bin/vhusbd

cat >/etc/systemd/system/vhusbd.service <<EOF
[Unit]
Description=vhusbd
After=network-online.target

[Service]
Restart=always
User=root
Group=root
ExecStart=/usr/bin/vhusbd

[Install]
WantedBy=multi-user.target
EOF

# Enable and start service
systemctl enable --now vhusbd.service

 

Posted by Uli Köhler in Networking

Cross-compiling boost for OpenWRT

This post showcases how to cross-compile boost for OpenWRT. We’ll use the Teltonika RUTX10 SDK which is already pre-configured with the relevant OpenWRT settings for that router.

The prerequisite for this is that you have:

We assume the SDK is located in ~/rutos-ipq40xx-rutx-gpl.

Compiling boost

First, you need to consider that many boost libraries are header-only libraries. For those libraries, you don’t need to compile boost, but it might still be easier to prepare a complete boost folder for installation.

First, download boost and unpack it. Now run

./bootstrap.sh

to compile bjam.

 

Now, open project-config.jam inside the boost folder and add the following line at the top of the file:

using gcc : openwrt : arm-openwrt-linux-muslgnueabi-g++ ;

Now, inside the boost folder, run the following bash script:

export STAGING_DIR=~/rutos-ipq40xx-rutx-gpl/staging_dir
export TOOLCHAIN=${STAGING_DIR}/toolchain-arm_cortex-a7+neon-vfpv4_gcc-8.4.0_musl_eabi
export CC=${TOOLCHAIN}/bin/arm-openwrt-linux-muslgnueabi-gcc
export CPP=${TOOLCHAIN}/bin/arm-openwrt-linux-muslgnueabi-g++
export PATH=$PATH:${TOOLCHAIN}/bin/

# Insert at the top of project-config.jam
# using gcc : openwrt : arm-openwrt-linux-muslgnueabi-g++ ;

rm -rf ~/boost_rutx10
mkdir -p ~/boost_rutx10/
./b2 --prefix=$HOME/boost_rutx10 install toolset=gcc-openwrt -sNO_COMPRESSION=1

Now, boost is installed in ~/boost_rutx10, which has include and lib subdirectories.

Posted by Uli Köhler in Boost, OpenWRT

How to build the Teltonika RUTX10 SDK in 5 minutes

  1. Download the SDK from the relevant router’s page, e.g. RUTX10 firmware downloads
  2. Unpack it
  3. ./scripts/feeds update -a
    
  4. make -i
  5. Wait until finished (it will typically take 30 minutes or so, depending on the computer.
Posted by Uli Köhler in OpenWRT

Does MikroTik RouterOS support secp384r1 certificates

Yes, RouterOS 7.9+ supports certificates with secp384r1 keys.

RouterOS versions before 7.9 possibly also support secp384r1 certificates but I have no older RouterOS available for testing at the moment.

Posted by Uli Köhler in MikroTik, Security

NodeJS MikroTik PoE status query example

This example builds on our previous posts NodeJS Mikrotik API minimal example and MikroTik RouterOS: How to power-cycle PoE using the terminal.

The following code will print the PoE status on Port ether5 on the given MikroTik device using the MikroTik API.

import * as MikroNode from 'mikrotik' ;

const host = "192.168.88.1";
const username = "admin";
const password = "admin1234"; // Hope that's not your real password ;)

const connection = MikroNode.getConnection(host, username, password, {
    closeOnDone : true
});

connection.getConnectPromise().then(function(conn) {
    conn.getCommandPromise(['/interface/ethernet/poe/print', '?name=ether5']).then(values => {
        console.log(values);
    }, reason => {
        console.log('Error while running command: ' + JSON.stringify(reason));
    });
}).catch(reason =>  {
    console.log('Error while connecting: ' + JSON.stringify(reason));
});

Example output:

[
  {
    '.id': '*5',
    name: 'ether5',
    'poe-out': 'forced-on',
    'poe-priority': '10',
    'poe-lldp-enabled': 'false',
    'power-cycle-ping-enabled': 'false',
    'power-cycle-interval': 'none',
    '.about': 'poe-out status: power_reset'
  }
]

If the PoE is currently being power-cycled, this will print:

[
  {
    '.id': '*5',
    name: 'ether5',
    'poe-out': 'forced-on',
    'poe-priority': '10',
    'poe-lldp-enabled': 'false',
    'power-cycle-ping-enabled': 'false',
    'power-cycle-interval': 'none',
    '.about': 'poe-out status: power_reset'
  }
]

 

Posted by Uli Köhler in MikroTik, NodeJS, PoE

MikroTik RouterOS: How to power-cycle PoE using the terminal

/interface/ethernet/poe/power-cycle ether-MyAccessPoint duration=5

 

Posted by Uli Köhler in MikroTik

NodeJS Mikrotik API minimal example

This is an example of access the Mikrotik API using NodeJS and the mikrotik package.

First, install the package

npm i --save mikrotik

Also, in order to enable import statement, set

"type": "module"

in package.json.

Example code:

import * as MikroNode from 'mikrotik' ;

const host = "10.56.23.4";
const username = "admin";
const password = "N@CdVTz8y@D$KwVS5TTo"; // Hope that's not your real password ;)

const  connection = MikroNode.getConnection(host, username, password, {
    closeOnDone : true
});

connection.getConnectPromise().then(function(conn) {
    conn.getCommandPromise('/ip/address/print').then(addresses => {
        for(const address of addresses) {
            console.info(`Address: ${address.address} on ${address.interface}`);
        }
    }, reason => {
        console.log('Error while running command: ' + JSON.stringify(reason));
    });
}).catch(reason =>  {
    console.log('Error while connecting: ' + JSON.stringify(reason));
});

This will output, for example:

Address: 192.168.88.1/24 on bridge
Address: 10.1.2.3/24 on bridge

In case of bad username/password credentials, it will print:

Error while connecting: {"errors":[{"category":"","message":"invalid user name or password (6)"}],"channelId":"login","channel":{"id":"login","running":true,"closing":true,"closed":true,"clearEvents":false,"saveBuffer":true,"closeOnDone":false,"lastCommand":["/login","=name=admin","=password=admin1234",".tag=login"],"_events":{},"_eventsCount":0}}

 

Posted by Uli Köhler in MikroTik, NodeJS

Joplin default username / password

The default credentials for the Joplin note app are:

  • Username: admin@localhost
  • Password: admin

Source: Server README on Github

Posted by Uli Köhler in Networking

How to fix MikroTik “Couldn’t add new IPv6 Pool – prefix length cannot be smaller than prefix (6)”?

Problem:

You are trying to add a new IPv6 pool with settings such as

But when you click OK, you see an error message Couldn't add new IPv6 Pool - prefix length cannot be smaller than prefix (6)

Solution:

You need to add the prefix length – e.g. /64 to the Prefix field as well:

Now click OK or apply and the error will disappear.

Important note: You might want to use a different Prefix Length here (typically it is smaller than the e.g. /64 at the end of the Prefix field so multiple prefixes can be extracted from the given pool.

Posted by Uli Köhler in MikroTik