OpenWRT: блокировка рекламы
Есть отличная прошивка на базе всеми любимого линупса для всякой разной техники вроде роутеров и микрокомпьютеров - это OpenWRT.
А поскольку эта штука работает в качестве локального днс-сервера, то грех не научить ее блокировать на корню всякие даблклик.нет и другое непотребство.
Рассматривать будем ситуацию при которой у нас установлена дефолтная конфигурация c dnsmasq.
Сначала нам потребуется поставить пакет dnsmasq-full взамен стандартного (он чуть больше по объему и тянет больше зависимостей, и предоставляет больше возможностей по настройке).
# opkg update
# opkg remove dnsmasq
# opkg install dnsmasq-full
# /etc/init.d/dnsmasq restart
Посмотрим на файл /tmp/etc/dnsmasq.conf. Нас будут интересовать следующие два параметра.
addn-hosts=/tmp/hosts
conf-dir=/tmp/dnsmasq.d
Буквально это значит, что дополнительные файлы в формате /etc/hosts хранятся в /tmp/hosts, а дополнительные конфиги - в /tmp/dnsmasq.d.
Теперь нам потребуется скрипт, который будет скачивать листы. Поместим его в /root/bin/adblock.sh
#!/bin/sh
echo "download adblock rules"
if [! -d /tmp/dnsmasq.d]; then
mkdir /tmp/dnsmasq.d
fi
if [! -d /tmp/hosts]; then
mkdir /tmp/hosts
fi
touch /tmp/dnsmasq.d/adblock.conf
wget -O /tmp/dnsmasq.d/adblock.conf "http://pgl.yoyo.org/adservers/serverlist.php?hostformat=dnsmasq&showintro=0&mimetype=plaintext"
echo "" > /tmp/hosts/adblock
wget -O /tmp/adblock https://hosts-file.net/ad_servers.txt
sed 's/^\(.*\).$/\1/' /tmp/adblock >> /tmp/hosts/adblock
wget -O /tmp/adblock https://adaway.org/hosts.txt
sed 's/^\(.*\).$/\1/' /tmp/adblock >> /tmp/hosts/adblock
wget -O /tmp/adblock http://winhelp2002.mvps.org/hosts.txt
sed 's/^\(.*\).$/\1/' /tmp/adblock >> /tmp/hosts/adblock
if [-f /tmp/adblock]; then
rm /tmp/adblock
fi
/etc/init.d/dnsmasq enabled && /etc/init.d/dnsmasq restart
Первым мы скачиваем файл с блокировками в формате dnsmasq, а последующие запросы - это блокировки в формате hosts. Соответственно раскладываем их по разным папкам и рестартим сервис.
Не забываем поставить +x на файл.
Теперь нужно добавить этот скрипт в крон дабы он обновлялся.
# crontab -e
и пишем туда что-то вроде
* */12 * * * /bin/sh /root/bin/adblock.sh
Это означает, что раз в 12 часов списки будут обновляться.
Естественно, что надо включить крон. По дефолту он выключен.
# /etc/init.d/cron enable
# /etc/init.d/cron enabled && /etc/init.d/cron start
Теперь осталось сделать так, чтобы при поднятии сетевого интерфейса скрипт сразу же обновлял правила.
А для этого нам потребуется создать файл /etc/hotplug.d/iface/50-adblock примерно следующего вида.
#!/bin/sh
[ifup = "$ACTION" -a "$DEVICE" = eth1] && {
/bin/sh /root/bin/update_adblock.sh
}
Где eth1 - это ваш wan-интерфейс.
Все. Можно перезагрузить роутер для проверки что все настроено корректно.
Рекламные домены вроде doubleclick.de должны резолвиться либо на 0.0.0.0, либо на 127.0.0.1.
$ nslookup doubleclick.de
Server: 192.168.0.1
Address: 192.168.0.1#53
Name: doubleclick.de
Address: 127.0.0.1
Чтобы точно убедиться, что все работает как надо - проверяйте что сразу после поднятия wan появились файлы /tmp/dnsmasq.d/adblock.conf и /tmp/hosts/adblock.
Учтите, что в сумме размер списков блокировки составит более 100 тысяч записей. И если роутер слабоват, то придется какой-то из списков отключать.
И да - это не панацея. Это просто хороший способ обезопасить электронные читалки, телефоны и разную мелкую технику, которая ходит в инет от баннеров и прочего добра.
Источники:
- https://wiki.openwrt.org/doc/networking/routing
- https://forum.openwrt.org/viewtopic.php?id=50407
- https://wiki.openwrt.org/doc/howto/cron
- https://wiki.openwrt.org/ru/doc/howto/dhcp.dnsmasq
- https://forum.openwrt.org/viewtopic.php?id=25304
- https://wiki.openwrt.org/doc/techref/initscripts
- https://wiki.openwrt.org/doc/techref/initscripts
- https://wiki.openwrt.org/ru/doc/uci/dhcp
JavaScript: копируем img в canvas
Существует несколько способов скопировать имеющееся на странице изображение (img) в canvas. Конечно все они сводятся к простейшему drawImage, но каждый из этих методов применим в своем контексте.
Первый и самый очевидный (а еще универсальный) - загрузить изображение при помощи объекта Image. Он работает только в случае, когда у img есть атрибут src.
var img = new Image();
var srcImg = document.getElementById('src-img');
img.onload = function() {
// создаем (или получаем) канву
var backCanvas = document.getElementById('dest-canvas');
backCanvas.width = this.width;
backCanvas.height = this.height;
var backCtx = backCanvas.getContext('2d');
// рисуем
backCtx.drawImage(this, 0,0);
};
img.setAttribute('src', srcImg.src);
Недостаток - еще один запрос в сеть.
Второй способ - менее универсален. Картинка у нас уже есть - почему ее нельзя нарисовать на канве?
var backCanvas = document.getElementById('dest-canvas');
var srcImg = document.getElementById('src-img');
backCanvas.width = srcImg.naturalWidth;
backCanvas.height = srcImg.naturalHeight;
var backCtx = backCanvas.getContext('2d');
// рисуем картинку
backCtx.drawImage(srcImg, 0,0);
И вот тут мы используем naturalWidth/naturalHeight. Зачем?
Все очень просто. Если в первом случае width и height означали размеры картинки, то во втором - это будут физические размеры элемента img на странице. И если картинка внутри него будет отмасштабирована, то мы мы скопируем только часть картинки размером width на height.
Как на иллюстрации ниже (картинка там имеет разрешение в десять раз больше нежели физические размеры img и масштабируется).
А свойства naturalWidth/naturalHeight не поддерживаются в ряде браузеров. поэтому способ универсальным назвать нельзя.
Xmonad: Фиксим менюшки у saleae logic
Есть довольно хороший бюджетный логический анализатор от saleae (и масса совместимых китайских клонов).
Что примечательно - это то, что ребята из этой конторы написали софт под все платформы (и не забыли линупс конечно же).
Софт написан на qt. И выглядит как бы совсем нестандартно.
В обычных DE с ним все нормально, но во всяких WM наступают грабли из-за нестандартной реализации менюшек. В частности очень сильно страдает xmonad. В нем при попытке открыть менюшки появляется цветная рамка и меню пропадает.
Фикс проблемы есть у саппорта saleae - нужно заигнорить окна с определенным классом добавив соответствующее правило к оконным хукам.
className =? "Logic" --> doIgnore
PHP: array_map и ключи массива
Интересно, почему такой вопрос часто всплывает на форумах или где-то еще?
Сначала постараюсь ответить на вопрос “нафига?”, а потом на вопрос “как?”.
Мы привыкли, что в в питоне, js и множестве других языков и фреймворков есть функция map, которая применяет некоторую функцию-обработчик к каждому элементу в списке данных и возвращающую результат в том же порядке. Пруф.
Но никто не ждал, что хеш-таблица и массив в контексте одного из языков будет означать одно и то же. Опять же пруф.
Этот постыдный момент из жизни структуры привел к тому, что одним из самых частых применений массивов (в пхп конечно же) стало создание отображений категория=>какое-то значение.
А после того как у вас появилось отображение вы, вероятно, захотите это где-нибудь на сгенерированной странице отобразить.
Т.е. показать пользователю сам параметр, а скобках его категорию.
Как мы делаем это в языках (фреймворках), которые разделяют понятие массива и хеш-таблицы? Перебираем объект, который содержит категории и формируем по нему массив выводимых данных. Наверное так.
И тут мы открываем руководство по php и видим, что она применяет некий колбек ко всем элементам массива и после этого возвращает новый массив.
Удобно же! Применили колбек к массиву и получили обработанный.
$array = [
'category1' => 'first category',
'category2' => 'second category',
];
var_dump(array_map(function(....
И что-то не заладилось. :) Ключи в колбек не попадают. Можно сделать все через foreach, но тогда нам потребуется еще одна переменная. А тут все было просто и наглядно.
И мы идем в гугель: “php array_map with keys”.
А зачем гуглить-то?
$array = [
'category1' => 'first category',
'category2' => 'second category',
];
var_dump(array_map(function($key, $value) {
return "{$key} => {$value}";
}, array_keys($array), $array));
И все отлично работает. И притом правильно. Относительно конечно же. И никаких вам лишних переменных.
А тем временем в коде вновь и вновь появляются конструкции вида
$array = [
'category1' => 'first category',
'category2' => 'second category',
];
$description = [];
foreach ($array as $key => $value) {
$description[] = "{$key} => {$value}";
}
Или еще хуже.
$array = [
'category1' => 'first category',
'category2' => 'second category',
];
$description = [];
array_walk($array, function($value, $key) {
$description[] = "{$key} => {$value}";
});
Проблема кейса из статьи может быть и раздута, но при вчитывании в сотни строк кода более-менее понятными сходу являются только первые два варианта.
Вариант же с array_walk
на понятность никак не претендует (как и решение подобной задачи при помощи .each в jquery).
Git: откат мержа, который не был запушен
Иногда мы делаем мерж некоторой ветки в master и случается такое, что нам нужно по какой либо причине откатить ветку (мы не делали push еще в удаленный репозитарий), либо просто пытаемся сделать git pull забыв, что есть непрокоммиченые изменения.
При git pull мы увидим следующую картину
Git Pull Failed
You have not concluded your merge (MERGE_HEAD exists). Please, commit your changes before you can merge.
И чтобы откатить наш неудачный мерж не нужно делать никаких reset –hard HEAD=1.
Достаточно сделать
git reset --hard ORIG_HEAD
Тем самым мы приводим локальную ветку мастера к виду, в котором она был до неудачного мержа.