9 / 2009

Petite présentation de sys/queue.h

date
26 / 9 / 2009
date
C
comments
2

Dans vos programmes C, il arrive très fréquemment d'utiliser des listes chaînée (de toutes sortes), afin de ne pas avoir à recréer le monde à chaque fois vous pouvez utiliser les macros super pratiques de queue(3). Voici une petite introduction à l'utilisation de sys/queue.h avant d'aller se plonger dans le man pour aller plus loin.

Avec sys/queue.h , vous pouvez manipuler facilement quatres sortes de listes :

  • Listes simplement chainées (SLIST) de type pile
  • Listes doublement chainées (LIST) de type pile
  • Listes simplement chainées (STAILQ) de type file
  • Listes doublement chainées (TAILQ) de type file

Voici un exemple de SLIST :

Le header :

#ifndef HEADER_H
#define HEADER_H

#include <sys/queue.h>

typedef struct MaStruct {
    /* ici on met nos elements par exemple : */
    char *str;

    /*
     * On déclare notre liste avec SLIST_ENTRY qui est equivalente à
     * struct { struct MaStruct *sle_next; } next;
     */

    SLIST_ENTRY(MaStruct) next;
} MaStruct;

#endif /* HEADER_H */

Ensuite voyons comment manipuler cette liste :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "header.h"

int
main(void)
{
    /* SLIST_HEAD crée une variable pour acceder à notre liste */
    SLIST_HEAD(, MaStruct) head;

    /* on crée un element MaStruct */
    MaStruct *p;

    /* On l'initialise à NULL */
    SLIST_INIT(&head);

    p = malloc(sizeof(*p));
    p->str = malloc(sizeof(char) * 10);
    strcpy(p->str, "blah");

    /* On insere p dans la SLIST */
    SLIST_INSERT_HEAD(&head, p, next);

    /* On empile un deuxième element */
    p = malloc(sizeof(*p));
    p->str = malloc(sizeof(char) * 10);
    strcpy(p->str, "blu");

    SLIST_INSERT_HEAD(&head, p, next);

    /*
     * Il est très facile de parcourir la liste
     * que ce soit pour du traitement ou de
     * la libération de mémoire
     */
    SLIST_FOREACH(p, &head, next) {
        /* ici p est l'element courant */
        printf("element : %s\n", p->str);
    }

    /* exemple de libération */
    while (!SLIST_EMPTY(&head))
    {
        p = SLIST_FIRST(&head);
        SLIST_REMOVE_HEAD(&head);
        free(p->str);
        free(p);
    }

    return 0;
}

Parmis les macros interessantes pour les SLIST il y a :

SLIST_FIRST(&head);                /* renvoie la tête de liste */
SLIST_REMOVE_HEAD(&head, next);    /* supprime la tete de liste */
SLIST_EMPTY(&head); /* renvoie vrai si la liste est vide */

Ben entendu, il y a beaucoup plus de possibilités avec LIST et TAILQ... Mais globalement vous devriez avoir compris le principe.

La lecture de sys/queue.h devrait vous éclairer pour comprendre comment marchent toutes ces macros, c'est assez facile à comprendre si vous avez (comme moi) un niveau moyen en C.

Voyez aussi ce papier d'iMil.

Nouveau blog

date
13 / 9 / 2009
comments
0

J'ai du mal à utiliser un logiciel sans savoir exactement comment il marche. En l'occurrence j'utilisais dotclear, un moteur de blog en php, je l'utilisais de façon basique sans les nombreuses fonctionnalités à coté (dont je ne connais pas plus le sens que le nom).

Quand un jour Bender B. Rodriguez me montre un template CSS qui me plait bien, j'avais déjà l'idée de coder mon propre blog derrière la tête et c'est parti pour coder ce nouveau blog from scratch en python bien sûr avec webpy.

Maintenant quand j'ai un bug ou un problème je peux régler le problème rapidement.

Pour ceux qui veulent essayer chez eux mon blog, le code est disponible via git :

$ git clone git://git.philpep.org/pblog.git

Pblog est donc écris en python avec le framework minimaliste webpy, avec des templates générés par makotemplates, le générateur html est markdown couplé avec pygments pour la coloration syntaxique, la base de données utilisé est MySQL mais ça doit pas être trop dur de l'utiliser avec d'autres DB.

Toute contribution est bienvenue, c'est fort probable que le code comporte une maxi faille donc noble hacker si tu la trouve merci de m'en faire part avant de l'avoir exploité :-)

Si vous trouvez que les pages mettent un temps fou à se générer j'ai ma petite idée là dessus, en fait j'utilise des jails, donc nous avons :

  • lenine.philpep.org avec les sites en php et le serveur MySQL
  • marx.philpep.org avec les sites en python

Donc, les requettes sql ne se font pas en localhost et il y a des latences non négligeables (le code n'étant pas super optimisé ça amplifie le truc).

La solution que j'envisage (à moins de tout optimiser avec du cache), c'est d'utiliser une db plus adaptée à cette petite appli web toute simple : sqlite.

Limiter un utilisateur avec pf

date
11 / 9 / 2009
comments
0

OpenBSD Packet Filter permet de filtrer les paquets suivant l'UID de provenance (et peut être même de destination mais ça nous intéresse moins.

Vous avez un amis qui se connecte en ssh chez vous pour poser un irssi dans un GNU screen. C'est super sympa de votre part, seulement si on a pas une confiance totale en cet utilisateur il pourrait (lui ou un virus) se servir de son accès pour utiliser votre IP et balancer du spam, lancer une attaque de banque ou je ne sais quoi encore. Résultat : vous êtes responsable.

L'idée est simple, nous allons filtrer le trafic sortant de cet utilisateur (de login fictif machin) en lui autorisant uniquement le port IRC 6667 :

pass out on $ext_if proto tcp to port 6667 user machin tag TAG_MACHIN
block out quick on $ext_if proto tcp all user machin ! tagged TAG_MACHIN

La première règle autorise le port 6667 sortant pour machin et tagge le paquet avec TAG_MACHIN. La deuxième bloque tout ce qui vient de machin et qui n'est pas taggé avec TAG_MACHIN. Ce qui fait exactement ce que l'on veut.

Le mot clef quick permet a la règle d'être prise en compte immédiatement peu importe les règles suivantes (ce qui protège d'une éventuelle règle qui ferait tout passer ensuite).

Pour continuer dans l'exemple, il peut être utile d'autoriser les query DNS pour cet utilisateur (si vous n'avez pas de serveur DNS en interne), ça se passe en 53/udp :

pass out on $ext_if proto tcp to port 6667 user machin tag TAG_MACHIN
pass out on $ext_if proto udp to port domain user machin tag TAG_MACHIN
block out quick on $ext_if proto tcp all user machin ! tagged TAG_MACHIN

On peut même faire des listes sur les port et/ou utilisateurs :

users = { machin, truc }
pass out on $ext_if proto tcp to port { 6667, http } user $users tag TAG_USERS
pass out on $ext_if proto udp to port domain user $users tag TAG_USERS
block out quick on $ext_if proto tcp all user $users ! tagged TAG_USERS

Bloquer le trafic sortant de ses jails avec packet filter

date
11 / 9 / 2009
comments
0

Si comme moi vous utilisez une FreeBSD avec pleins de services/utilisateurs dans des jails, il vous est peut être arrivé de vouloir restreindre un peu plus le possibilité réseau dans vos jails. Par exemple empêcher qu'un de vos utilisateur (réel ou non) utilise votre IP pour faire des choses malsaine (un script qui envoie du spam par exemple).

Pour cela j'utilise Packet filter et ses tags. Le problème c'est qu'une fois que la NAT pour les jails est écrite, le paquet apparaît comme provenant de l'hôte et non de la jail. Comme toujours un bon fichier de conf vaut mieux qu'un long discourt :

ext_if = "fxp0"

# Network Description 
jails   = "10.0.0.0/24"    # Jails

set block-policy return
set skip on { lo0, lo1 }
set loginterface $ext_if
scrub in

# Nat for jails, we tag these packets to make filtering on out packets
nat on $ext_if from $jails  tag TAG_JAILS  -> $ext_if

# Block rules
block log all

# Pass out rules
pass out on $ext_if proto { tcp, udp } all ! tagged TAG_JAILS
pass out on $ext_if proto tcp to port { http ftp ircd  6697 domain 9418 } tagged TAG_JAILS
anchor "ftpsesame/*" on $ext_if

# Antispoofing
antispoof log for { $ext_if, lo0 } inet

Voilà, quand le paquet arrive sur la NAT, il est taggé avec TAG_JAIL et on effectue du filtrage ensuite sur ce tag, tout le trafic sortant passe pour les paquets qui ne proviennent pas des jails et le traffic qui provient des jails passe uniquement si le port de direction est autorisé. L'ancre "ftpsesame/*" est là pour autoriser le traffic sortant ftp, ce qui n'est pas aussi évident que l'on pense, voir ce billet.

Packet filter et ftp sortant

date
11 / 9 / 2009
comments
2

Comme j'ai expliqué dans ce billet, filtrer le traffic sortant est une bonne habitude à avoir, surtout pour un serveur qui utilise tout le temps les même ports sortant.

Le problème c'est le protocole FTP qui a été crée a un moment où la sécurité n'existait pas encore et on se connectait en telnet sans mot de passe. FTP n'est pas fait pour passer les parre feu. Si la connection est initié sur le port 21 le transfert des données se fait sur un autre port qui est négocié soit par le serveur soit par le client (Mode actif et mode passif). Du coup rend le filtrage beaucoup plus compliqué puisqu'on ne connait pas d'avance le port qui va être utilisé.

Après avoir lu la doc pour gerer le protocole FTP avec packet filter, j'ai essayé d'utiliser ftp-proxy et tous mes tests se sont soldés par un cuisant echec. Il semblerais que ftp-proxy ne soit pas adapté pour un client en ftp passif protégé par un parre feu local avec un filtrage strict des paquets sortants.

J'ai donc trouvé par miracle dans les ports FreeBSD un petit programme qui permet de regler le problème sans trop de difficultés.

(Remplacez rl0 par votre interface réseau)

make -C /usr/ports/ftp/ftpsesame install clean
echo "ftpsesame_enable=\"YES\"\nftpsesame_flags=\"-i rl0\"\n" >> /etc/rc.conf

Et la conf pf qui va avec :

# L'interface connecté au réseau local
ext_if = "rl0"

# Les ports sortant autorisés
out_tcp  = "{ ssh http ftp https 1213 6600 8000 8021 9418 xmpp-client 5223 }"
out_udp  = "{ domain }"

# Options
set loginterface $ext_if
set skip on lo0
scrub in

# Filtering, on bloque tout et on passe ce qui est autorisé
block log all
pass out on $ext_if proto icmp all
pass out on $ext_if proto udp to port $out_udp
pass out on $ext_if proto tcp to port $out_tcp
# On charge les rêgles de ftpsesame
anchor "ftpsesame/*" on $ext_if

# Antispoofing
antispoof log for { $ext_if, lo0 } inet

Et hop :

/usr/local/etc/rc.d/ftpsesame start
pfctl -f /etc/pf.conf

Franchement je sais pas comment ftpsesame se débrouille mais ça marche impécablement.