Hungry Mind , Blog about everything in IT - C#, Java, C++, .NET, Windows, WinAPI, ...

WL-500gP HP 2015 problems

Нудавно я писал про подключение HP LaserJet 2015 к WL-500gP. Ну, вот и нашлись проблемы:

  1. Печать PostScript не работает.

    При печати через драйвер PostScript рутер пишеть в лог такие строчки:

    [lpr.notice] p9100d[88]: Connection from 192.168.1.4 port 51240 accepted
    [kern.warning] kernel: printer.c: usblp0: nonzero read/write bulk status received: -71
    [kern.err] kernel: printer.c: usblp0: error -71 reading printer status
    
  2. Печать больших документов не работает. Даже через PCL 5/6.

    В логе анологичные строки и я подозреваю, что это, как и в первом случае, связанно с нехваткой оперативной памяти устройства.

Что тут еще говорить? Попытаюсь еще через CUPS и HPLIP, но последний не удалось скомпилировать. Да, все из-за той же нехватки оперативной памяти.

Я уже себе с трудом представляю, как рутер способен работать при 1-2 Mb свободной памяти. Это конкретно сужает область его задач.

Bosses and Jeeps

Вот мне интересно, это только на постсоветском пространстве у всех начальников-старперов имеется привычка при получении крупной суммы денег сразу покупать себе новый джип, не думая о том, как платить людям зарплату?

И еще Тарас, мой сотрудник, сегодня отмочил:

Если начальник приезжает на работу на новой крутой тачке - значит компания процветает. А если программисты приходят на работу в рванных кроссовках, то понятно, за чей счет.

Hacking WL-500gP Part 1

Ну, вот я и добрался до своего ненаглядного рутера WL500gP. За последние пару дней на плечи ему свалилось немало:

  1. SSH
  2. 4 Gb Flash
  3. Установка пакетов
  4. syslog-ng
  5. Создание пользователей
  6. VSFTPD
  7. Samba 3
  8. Cron
  9. Firewall

Все это поверх прошивки от Олега. Рекомендую глянуть на инструкцию по установке. Итак, по порядку.

Подготовка

Возможность управлять загрузкой рутера по-сути одна - файлы /usr/local/sbin/post-*, которые выполняются в таком порядке:

  1. post-firewall

    Выполняется сразу после инициализации сетевых устройств. Скрипту система передает параметры - WAN-интерфейс, WAN-адрес, Bridge-интерфейс, Bridge-адрес:

    /usr/local/sbin/post-firewall vlan1 wan.ip.ad.dr br0 lan.ip.ad.dr
    
  2. post-boot

    Параметрами не интересовался.

  3. pre-mount

    Параметрами не интересовался. Выполняется только, если есть что монтировать.

  4. post-mount

    Параметрами не интересовался. Выполняется только, если есть что монтировать.

  5. pre-shutdown (при перегрузке рутера)

    Параметрами не интересовался.

Я создал файл /usr/local/sbin/post-include с полезными переменными такого содержания:

#!/bin/sh

self=`basename $0`
log="/usr/bin/logger -t $self"

Изначально каждый файл /usr/local/sbin/post-* у меня выглядит так:

#!/bin/sh

. "`dirname $0`/post-include"

$log 'Begin'

# initialization here

$log 'End'

А /usr/local/sbin/pre-shutdown так:

#!/bin/sh

. "`dirname $0`/post-include"

[ -x /opt/bin/logger ] && log="/opt/bin/logger -p Syslog.Alert"

$log 'Shutting down system.'

# BEGIN services termination
if [ `pidof vsftpd` -ne "" ]; then
        $log 'Terminating vsftpd'
        /bin/kill `pidof vsftpd`
fi

if [ `pidof smbd` -ne "" ]; then
        $log 'Terminating smbd'
        /bin/kill `pidof smbd`
fi
if [ `pidof nmbd` -ne "" ]; then
        $log 'Terminating nmbd'
        /bin/kill `pidof nmbd`
fi

if [ -f /var/run/lighttpd.pid ]; then
        $log 'Terminating lighhttpd'
        /bin/kill `cat /var/run/lighttpd.pid`
fi

if [ -f /opt/var/run/cron.pid ]; then
        $log 'Terminating cron'
        /bin/kill `cat /opt/var/run/cron.pid`
fi

if [ -f /var/run/syslog-ng.pid ]; then
        $log 'Terminating syslog-ng'
        /bin/kill `cat /var/run/syslog-ng.pid`
fi

if [ -f /var/run/dropbear.pid ]; then
        $log 'Terminating dropbear'
        /bin/kill `cat /var/run/dropbear.pid`
fi

# END services termination

if [ -d /tmp/harddisk/opt ]; then
        $log 'Unmounting FlashFS'
        /bin/umount /tmp/harddisk
        /bin/umount /opt
fi

pre-shutdown аккуранто останавливает все службы и в конце размонтирует файловую систему.

Для сохранения файлов не с флешки в ПЗУ устройства необходимо выполнить следующую команду: flashfs save && flashfs commit && flashfs enable. Я постоянно забывал сохраняться и после перегрузки набивал изменения снова. Для сохранения файлов в других каталогах необходимо добавить пути в файл /usr/local/.files.

Исполняемым файлам не забывать делать chmod +x file.

SSH

Выполнить:

mkdir -p /usr/local/etc/dropbear
dropbearkey -t dss -f /usr/local/etc/dropbear/dropbear_dss_host_key
dropbearkey -t rsa -f /usr/local/etc/dropbear/dropbear_rsa_host_key

Для автоматического запуска SSH сервера (dropbear) нужно добавить в файл /usr/local/sbin/post-boot следующие строчки:

$log 'Starting dropbear SSH server'
/usr/sbin/dropbear 1>/dev/null 2>&1

В конце:

flashfs save && flashfs commit && flashfs enable

Также необходимо добавить парочку правил в файрвол. Для этого правим /usr/local/sbin/post-firewall:

$log 'SSH rules'
iptables -I INPUT 5 -i $1 -p tcp -d $2 --dport 22 -m state --syn --state NEW -m limit --limit 2/minute --limit-burst 1 -j LOG --log-prefix "SSH Brute force attack: " --log-level 6
iptables -I INPUT 6 -i $1 -p tcp -d $2 --dport 22 -m state --syn --state NEW -m limit --limit 2/minute --limit-burst 1 -j ACCEPT
iptables -I INPUT 7 -i $1 -p tcp -d $2 --dport 22 -m state --syn --state NEW -j DROP

4 Gb Flash

Флешка нужна для установки дополнительного софта, ну, и для хранения файлов, конечно. Также устройство может загружаться с флешки! Но мне это пока не нужно.

Для пробы имелась 512 Mb флешка, на которую ядро сильно ругалось. Пришлось ставить 4 Gb Pretec. Поскольку из самого устройства разбить на разделы не получилось, я использовал Acronis Disk Director 10. Получилось два раздела - Linux swap на 100 с копейками мегабайт и Linux ext3 - остальное.

Через веб морду я отключил встроенный FTP и Samba. В результате не загружались необходимые модули ядра - scsi_mod, sd_mod, usb-storage (как последствие - не выполнялись скрипты pre-mount и post-mount). Их нужно загрузить самостоятельно в /usr/local/sbin/post-boot:

/sbin/insmod scsi_mod
/sbin/insmod sd_mod
/sbin/insmod usb-storage

Что в результате:

  • Ядро пишет: /dev/scsi/host0/bus0/target0/lun0: p2 < p5 p6 >

    p5 (/dev/discs/disc0/part5) - swap, p6 (/dev/discs/disc0/part6) - ext3

  • /dev/discs/disc0/part6 смонтирован как /tmp/harddisk
  • На ext3 создана простейшая структура Unix-каталогов

Установка пакетов

В системе имеется простенький менеджер пакетов - ipkg. По умолчанию весь софт ставится в /opt, поэтому нужно, чтобы в /opt был смонтирован корень ext3. Для этого изменяем /usr/local/sbin/post-mount (вставляем в самое начало после $log 'Begin') :

[ -d /tmp/harddisk/opt ] && $log 'Mounting /opt' && /bin/mount -o bind,sync,noatime,rw /tmp/harddisk /opt

Выполнить (все это описано здесь):

ipkg.sh update
ipkg.sh install ipkg-opt
ipkg update
echo "/etc/ipkg.conf" >> /usr/local/.files
flashfs save && flashfs commit && flashfs enable

Ставим необходимый софт:

ipkg install adduser
ipkg install bash
ipkg install coreutils
ipkg install findutils
ipkg install grep
ipkg install less
ipkg install mc
ipkg install screen
ipkg install util-linux
ipkg install vim
ipkg install which
ipkg install wget-ssl

syslog-ng

syslogd я сразу меняю на syslog-ng. Ставим:

ipkg install syslog-ng
cd /opt/etc
ln -s syslog-ng/syslog-ng.conf syslog-ng.conf

Добавляем в /usr/local/sbin/post-mount:

if [ -x /opt/sbin/syslog-ng ]; then
        $log 'Replacing syslogd'
        [ -x /opt/bin/unlink ] && /opt/bin/unlink /tmp/syslog.log && /opt/bin/ln -s /opt/var/log/all.log /tmp/syslog.log
        kill `/bin/pidof syslogd`
fi

Это, естественно, должно выполнятся до запуска syslog-ng.

\

Не забываем также про остановку системы, файл /usr/local/sbin/pre-shutdown (как можно позже, но перед размонтированием):

if [ -f /var/run/syslog-ng.pid ]; then
        $log 'Terminating syslog-ng'
        /bin/kill `cat /var/run/syslog-ng.pid`
fi

rc.unslung и init.d

Многие пакеты закидывают скрипт запуска службы в /opt/etc/init.d/ с названием SXYService. Нужен механизм, который будет выполнять их в правильном порядке. Создаем исполняемый файл /opt/etc/init.d/rc.unslung с таким содержимым:

#!/bin/sh

# Start all init scripts in /opt/etc/init.d
# executing them in numerical order.
#
for i in /opt/etc/init.d/S??* ;do

    [ ! -f "$i" ] && continue
    [ ! -x "$i" ] && continue

    case "$i" in
       *.sh)
           # Source shell script for speed.
           (
               trap - INT QUIT TSTP
               set start
               . $i
           )
           ;;
       *)
           # No sh extension, so fork subprocess.
           $i start
           ;;
   esac
done

Добавляем вызов /opt/etc/init.d/rc.unslung в конец /usr/local/sbin/post-mount:

[ -x /opt/etc/init.d/rc.unslung ] && $log 'Running rc.unslung' && /opt/etc/init.d/rc.unslung | $log

Запуск syslog-ng из init.d

Теперь происходит автоматически благодаря /opt/etc/init.d/S01syslog-ng.

Настройка syslog-ng

Мой syslog-ng помимо файлов логирует еще и на рабочую машину, где стоит Kiwi Syslog в качестве приемника. Просто привожу конфиг /opt/etc/syslog-ng.conf:

#
# Syslog-ng example configuration for for NSLU2 Unslung 3.x
#
# Copyright (c) 1999 anonymous
# Copyright (c) 1999 Balazs Scheidler
# $Id: syslog-ng.conf 5159 2007-01-12 20:37:44Z fcarolo $
#
# Syslog-ng configuration file, compatible with default Debian syslogd
# installation.
#

options {
        long_hostnames(off);
        sync(0);
        stats(0);
        create_dirs(yes);
        time_reopen(10);
        log_fifo_size(2000);
};

source src {
        pipe("/proc/kmsg" log_prefix("kernel: ") );
        unix-stream("/dev/log");
        internal();
};
#source net { udp(); };

destination authlog { file("/opt/var/log/auth.log"); };
destination syslog { file("/opt/var/log/syslog"); };
destination cron { file("/opt/var/log/cron.log"); };
destination daemon { file("/opt/var/log/daemon.log"); };
destination kern { file("/opt/var/log/kern.log"); };
destination lpr { file("/opt/var/log/lpr.log"); };
destination user { file("/opt/var/log/user.log"); };
destination uucp { file("/opt/var/log/uucp.log"); };
destination ppp { file("/opt/var/log/ppp.log"); };
destination mail { file("/opt/var/log/mail.log"); };

destination mailinfo { file("/opt/var/log/mail.info"); };
destination mailwarn { file("/opt/var/log/mail.warn"); };
destination mailerr { file("/opt/var/log/mail.err"); };

destination newscrit { file("/opt/var/log/news/news.crit"); };
destination newserr { file("/opt/var/log/news/news.err"); };
destination newsnotice { file("/opt/var/log/news/news.notice"); };

destination debug { file("/opt/var/log/debug"); };
destination messages { file("/opt/var/log/messages"); };

destination udp_machinename { udp( your.ip.add.rr port(514) template("$DATE $FULLHOST [$FACILITY.$LEVEL] $MESSAGE\n") template_escape(no) ); };
destination alllog { file("/opt/var/log/all_$R_YEAR-$R_MONTH-$R_DAY.log" template("$DATE $FULLHOST [$FACILITY.$LEVEL] $MESSAGE\n") template_escape(no) ); };

filter f_auth { facility(auth); };
filter f_authpriv { facility(auth, authpriv); };
filter f_syslog { not facility(authpriv, mail); };
filter f_cron { facility(cron); };
filter f_daemon { facility(daemon); };
filter f_kern { facility(kern); };
filter f_lpr { facility(lpr); };
filter f_mail { facility(mail); };
filter f_user { facility(user); };
filter f_uucp { facility(cron); };
filter f_ppp { facility(local2); };
filter f_news { facility(news); };
filter f_debug { not facility(auth, authpriv, news, mail); };
filter f_messages { level(info..warn) and not facility(auth, authpriv, mail, news); };
filter f_emergency { level(emerg); };

filter f_info { level(info); };
filter f_notice { level(notice); };
filter f_warn { level(warn); };
filter f_crit { level(crit); };
filter f_err { level(err); };

log { source(src); filter(f_authpriv); destination(authlog); };
log { source(src); filter(f_syslog); destination(syslog); };
log { source(src); filter(f_cron); destination(cron); };
log { source(src); filter(f_daemon); destination(daemon); };
log { source(src); filter(f_kern); destination(kern); };
log { source(src); filter(f_lpr); destination(lpr); };
log { source(src); filter(f_mail); destination(mail); };
log { source(src); filter(f_user); destination(user); };
log { source(src); filter(f_uucp); destination(uucp); };
log { source(src); filter(f_mail); filter(f_info); destination(mailinfo); };
log { source(src); filter(f_mail); filter(f_warn); destination(mailwarn); };
log { source(src); filter(f_mail); filter(f_err); destination(mailerr); };
log { source(src); filter(f_news); filter(f_crit); destination(newscrit); };
log { source(src); filter(f_news); filter(f_err); destination(newserr); };
log { source(src); filter(f_news); filter(f_notice); destination(newsnotice); };
log { source(src); filter(f_debug); destination(debug); };
log { source(src); filter(f_messages); destination(messages); };
log { source(src); filter(f_ppp); destination(ppp); };

log { source(src); destination(udp_machinename); };
log { source(src); destination(alllog); };

Создание пользователей

Добавляю командой adduser (можно и напрямую править /etc/passwd и /etc/group). Не забываю сделать

echo "/etc/passwd" >> /usr/local/.files
echo "/etc/group" >> /usr/local/.files
flashfs save && flashfs commit && flashfs enable

Домашние папки создаю в /opt/home.

Sun Microsystems bought MySQL

Sun Microsystems Announces Agreement to Acquire MySQL, Developer of the World's Most Popular Open Source Database

Sun Growth Strategy Accelerates With New Position in $15 Billion Database Market SANTA CLARA, CA January 16, 2008 Sun Microsystems, Inc. (NASDAQ: JAVA) today announced it has entered into ... read more

Все, не будет больше J2EE на Оракле работать. MySQL станет круче всех! Гггг

Type system covariance and contravariance

Полагаю, многие разработчики не знают, что такое ковариантность/контравариарность системы типов. К примеру, в версии 1.5 языка Java появилась возможность использовать тип класса-наследника в объявлении замещающей функции:

 0: /**
 1:  *
 2:  */
 3: package com.chabster.covariance;
 4:
 5: /**
 6:  * @author Chabster
 7:  */
 8: public class Container
 9: {
10:   class A
11:   {
12:      A some() {
13:         return (this);
14:      }
15:   }
16:
17:   class B extends A
18:   {
19:      @Override
20:      B some() {
21:         return (this);
22:      }
23:   }
24:
25: }

В С++ такая возможность существует уже давно, а вот в C# все еще отсутствует. Полагаю, это связано с нестыковкой сигнатур методов в C# и IL. Вот, что говорит по этому поводу Standard ECMA-335 Common Language Infrastructure (CLI) 4th edition (June 2006):

A method signatures is composed of

  • a calling convention,
  • the number of generic parameters, if the method is generic,
  • a list of zero or more parameter signatures—one for each parameter of the method—and,
  • a type signature for the result value, if one is produced.

Получается, что IL код различает методы, которые отличаются лишь типом возврата, а C# - нет. Как и любой существующий на данный момент управляемый .NET-язык. С другой стороны этот недостаток можно элементарно восполнить. Вариант реализации предлогаю расценивать, как домашнее задание для читателя :).

В некоторых моментах C#, все же, поддерживает ковариантность и контравариантнось. Но для начала выясним что это такое.

Ковариантность (covariance) и контравариантнось (contravariance)

Ковариантностью называют сохранение формы при преобразовании. Соответсвенно, ковариантным называется преобразование, сохраняющее форму (свойства).

Например, оператор F(x) = x*2 является ковариантным касательно отношения % (делимость). Т.е. из x%y следует, что F(x)%F(y).

Контравариантностью называют обращение формы при преобразовании. Соответсвенно, контравариантным называется преобразование, обращающее форму.

Например, оператор F(x) = -x является контравариантным касательно отношения > (больше). Т.е. из x>y следует, что F(x)<F(y).

Оба этих понятия нельзя правильно обобщить поскольку в каждой науке оно выглядит по-своему. Рассмотрим их в самой интересной для нас области - программирование!

Ковариантность и контравариантнось в системе типов языков программирования

Рассмотрим пример C# кода:

class A {
    A[] aArr = new B[] { };
}

class B : A {
}

Пусть « обозначает отношение is a для типов. Поэтому B«A. Оператор Arrize({T}) = {T[]} является ковариантным касательно отношения is a для ссылочных типов т.к. из B«A следует B[]«A[].

Возвращаясь к первому Java примеру можно сказать, что оператор Methodize({SuperT virtMethod(T1,T2,...)}) = {SubT virtMethod(T1,T2,...)} является ковариантным касательно отношения override между методами.

Ковариантность и контравариантнось в системе типов C#

В C# есть ковариация, связанная с делегатами:

class A {
}

class B : A {
}

delegate A SomeDelegate();

static B SomeMethod() { return (null); }

static SomeDelegate sd = SomeMethod;

Типы возвращаемых значений метода и делегата различны, но совместимы.

В C# есть и контравариация, связанная с делегатами:

class A {
}

class B : A {
}

delegate void SomeDelegate(B b);

static void SomeMethod(A a) { }

static SomeDelegate sd = SomeMethod;

Сигнатуры метода и делегата различны, но совместимы, правда, уже в обратном направлении.

Это все, конечно, хорошо, вот только...

class A {
}

class B : A {
}

delegate T SomeDelegate<T>();

static B SomeMethod() { return (null); }

static SomeDelegate<B> sdB = SomeMethod;

static SomeDelegate<A> sdA = sdB;

... последняя строчка вызывает ошибку компиляции.

В целом, вариантность - очень полезный механизм, если им правильно пользоваться.

Copyright 2007-2011 Chabster