History of a bug

Raspberry as network monitor

Rédigé par gorki Aucun commentaire

Problem :

I built a network monitoring solution following this guides :

Truly, a great job.

But I has build the solution at home for another network, I would like that my raspberry start and monitor at boot. And I missed in the comments or text a few thing.

Solution :

I created services as described in the comment for prometheus, add another for the tcpdump. Don't forget prometheus working directory in this configuration (no specific user for prometheus).


ExecStart=/home/pi/prometheus/prometheus-2.23.0.linux-armv7/prometheus \
    --config.file /home/pi/prometheus/prometheus.yml


Description=TCPDump service for traffic monitoring
ExecStart=python3 /home/pi/network-traffic-metrics/network-traffic-metrics.py "(src net and not dst net or (dst net and not src net"

But I had some network issues :

First, disable dhcpcd and install isc-dhcp-server

In my case, I keep dhcpcd as it mount the network interfaces eth0 & eth1. I also put a no gateway on eth0 (my lan part)

My dhcpcd.conf configuration for interfaces :

interface eth1
static ip_address=
static routers=
static domain_name_servers=
static domain_search=

interface eth0
static ip_address=
static routers=
static domain_name_servers=
static domain_search=

But with this configuration, at boot :

  • isc-dhcp-server and tcpdump

were not started because eth0 was not up or plugged. In my case, I could plug eth0 later.

So I took a while, but I found the network hook that works (forget all /etc/network thing, dhcpcd do not use it).

Create a file (not a directory...) called /etc/dhcpcd.exit-hook with


if [ "$interface" = "eth0" & "$reason" = "STATIC" & "$if_up" = "true" ]
	systemctl start tcpdump
	systemctl start isc-dhcp-server.service

And all is starting when eth0 is going up.

IE11 et cache-control rules

Rédigé par gorki Aucun commentaire

Problem :

I had a problem, nearly simple : on an angular 11 application, font was not displayed on IE11 on customer site.

After a few tests :

  • I reproduce it on my demo site
  • I do not reproduce in dev mode

Solution :

Well, I search for a while, and here is a summary.

  1. IE11 has a problem if header "Cache-Control: nostore" is set for fonts... Not easy to find but there is some reference here
  2. On my dev, it's working, after a check, I'm not setting Cache-Control: nostore
  3. On my demo site, I have this header, but I have a Nginx as a reverse proxy. Ok, that's why
  4. On customer site, I do not have control on network elements. One must add it also

I made the assumption that if I set a Cache directive, intermediate server won't modify it.

It works on my demo site. I'll check next on my customer site.

To add cache control on springboot, thanks Baeldung !




Back to basics : hashcode and hashmap

Rédigé par gorki Aucun commentaire

Problem :

I'm building a Java agent to monitor objects. I track some objects and get metrics ont it. But to have less impact on memory, if objects are removed, I don't want to keep a reference to them. It could prevent the garbage collector to remove them.

Objects can be scanned multiple time for some reasons, so to keep a unique reference, I built an hashmap to track only one reference of these objects.

A hashmap with weak reference.

As stated by this article, weak reference can not be compared regarding their reference but only between WeakReference objects themselves. So I used the proposal of this article and create a WeakEqualReference object.

Adding is working well.

But after a while, I can not remove an object : I go through the map, I tried to remove an object given by the entrySet iterator : impossible.

Solution :

Well, I search for a while, and here is a summary.

In the article, hashcode used for WeakEqualReference is :

	public int hashCode() {
		T value = this.get();
		return value != null ? value.hashCode() : super.hashCode();

In fact, it gives :

  1. on the first call : the hashcode of the value
  2. on the second call, after value has been removed : the hashcode of the WeakEqualsReference

But when object is stored in the hashmap, this is the first hashcode which is used. And the hashmap never find the new hashcode after the value becomes null. Containskey, remove, all is wrong.

Hashcode must be consistent for the duration of the WeakEqualsReference.

So, my solution is to compute the hascode on the first call, when the object is stored in the hashmap, return it each times after that. WeakEqualsReference can now be removed safely.

import java.lang.ref.WeakReference;

public class WeakEqualReference<T> extends WeakReference<T> {

	private int hashCode = 0;

	public WeakEqualReference(T r) {

	public boolean equals(Object other) {

		boolean returnValue = super.equals(other);

		// If we're not equal, then check equality using referenced objects
		if (!returnValue && (other instanceof WeakEqualReference<?>)) {
			T value = this.get();
			if (null != value) {
				T otherValue = ((WeakEqualReference<T>) other).get();

				// The delegate equals should handle otherValue == null
				returnValue = value.equals(otherValue);

		return returnValue;

	public int hashCode() {
		if (hashCode == 0) {
			T value = this.get();
			hashCode = value != null ? value.hashCode() : super.hashCode();
		return hashCode;

And for the story :

- one of my values referenced was a bean with a String and another instance of WeakEqualsReference. I still had issue, but due to the String ! This string value was updated so hashcode before and after was different. Same cause, same effects.

Here the example was complicated by the WeakReference usage, but with a simple HashSet :

import java.util.HashSet;
import java.util.Objects;

public class HashCodeTest {

    public static class HashTestValue {
        public String value;

        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            HashTestValue that = (HashTestValue) o;
            return Objects.equals(value, that.value);

        public int hashCode() {
            return Objects.hash(value);

    public static void main(String... args) {

        HashSet<HashTestValue> set = new HashSet();

        HashTestValue mapTestValue = new HashTestValue();
        mapTestValue.value = "1234";

        System.out.println("set.contains(mapTestValue) = " + set.contains(mapTestValue));

        mapTestValue.value = "5678";

        System.out.println("set.contains(mapTestValue) = " + set.contains(mapTestValue));


Conclusion : overriding equals and hascode is OK, but be careful of the consistency if you need to test the object after the insert !


Springboot & listening address

Rédigé par gorki Aucun commentaire

Problème :

J'ai une configuration un peu particulière :

  • je développe et teste majoritairement sous Linux, Ubuntu
  • pour certains cas, je lance une VM Windows 10 sous virtualbox pour tester IE/Edge

Je lance comme d'habitude mon application, j'essaie de m'y connecter depuis la VM impossible...

Configuration de la VM :
- en NAT
- en virtual network

Solution :

Evidemment je pense au paramètre `server.address` de Spring boot car j'ai un log qui m'affiche : Listening on
Mais ça ne marche pas...

Je tente X configurations différentes : dans le fichier de configuration, en paramètre avec le -Dserver.address

Je tente avec le port forwarding NAT de Virtualbox. Nada.

La connexion SSH fonctionne : je peux me connecter depuis la VM

Je vérifie le firewall, pas activé.

Jé vérifie IPTables, ça me semble OK

Le netstat a du mal à sortir les LISTEN, j'utilise : lsof -i -P -n | grep LISTEN

Et là :

1) Springboot écoute bien par défaut sur toutes les IPv4, comme décrit a plein d'endroit, le server.address fonctionne très bien
2) le log affiché était applicatif et codé en dur : argh :(
3) c'était le iptable qui bloquait...  il fallait regarder le FORWARD et pas le INPUT... pas sur d'avoir compris pourquoi, a priori on ne change pas de réseau/machine. A creuser. Commande iptable pour ouvrir le port.




Openvpn et serveurs du réseau ne réponde pas au ping

Rédigé par gorki Aucun commentaire

Problème :

Après avoir eu un reboot de serveur, j'ai du perdre une configuration quelque part et mon VPN ne marchait plus correctement.

J'ai un serveur A qui héberge OpenVPN en avec un VLAN en

  • la connexion était OK
  • le ping du serveur A qui héberge openVPN était OK (sur l'adresse du VPN et du VLAN)
  • le ping du serveur B était KO sur l'adresse du VLAN

Solution :

Alors je n'ai sans doute pas la bonne configuration, c'est du vite réparé, je creuserai plus tard.

1) il faut activer l'IP forwarding sur le serveur A et je pense qu'après le reboot, le paramètre n'était pas permanent. C'est facile, c'est partout sur le net

Comme ça ne marchait pas, j'ai procédé par étape et c'est plus ça qui est intéressant.

2) Faire des tcpdump sur les différentes interfaces :

  •  tcpdump -nni tun0 icmp sur le serveur A, si on voit du traffic on continue
  •  tcpdump -nni eth0.vlan icmp sur le serveur A, là c'était KO, activation de l'IP forwarding, si OK on continue
  •  tcpdump -nni eth0.vlan icmp sur le serveur B alors là, les paquets arrivent bien au 2nd serveur
  • depuis le serveur A, pinger le client
  • depuis le serveur B pinger le client

Et là était mon problème, j'ai tilté après quelques lectures que les paquets arrivent avec une adresse en (VPN) au serveur en VLAN et il ne sait pas comment les renvoyer.

Solution rapide, sur le serveur B, ajouter une route :

route add -net gw netmask dev eth0.vlan

Mais il doit y avoir des façons de faire plus adaptés, si j'avais un réseau entreprise, je devrais ajouter cette route sur tous mes serveurs.

Donc piste à suivre :

iptables -t nat -A POSTROUTING -o <eth0 or whatever else> -j MASQUERADE
  • dernier point, mais a priori ne s'applique pas à mon cas, lorsque le serveur openvpn ne sait pas retrouver les clients ce blogavec l'option iroute (voir ce blog)



Fil RSS des articles