Block Greek ads with Internet Explorer 9+

Greek Adblock Plus filter list has more than 3500 regular unique (as per IP) subscribers daily. The majority of them uses some Mozilla-based browser (Firefox/Iceweasel). An increasing number of users has started using Chrome along with the Chrome Adblock Extension and Opera. Thanks to Panagiotis Dimopoulos, Greek Adblock Plus filter has now been converted to a Tracking Protection List for Internet Explorer 9+.

To load the protection list visit the url: Greek Adblock Tracking Protection List for Internet Explorer 9+

For more details about using Greek Adblock Plus filter on various browsers please visit: Greek Adblock Plus Filter.

Don’t forget to send in comments and URLs to block. If you are using Firefox’s addon, please use the “Report Issue on this page…” feature of it by right clicking on the status icon of adblock.

Why vacation auto-reply messages can sometimes be bad

Say that a user has an email account at the company he works for. Before going on vacation he activates his cool “vacation auto-reply” feature that adds

Out of Office – I will be back from holidays at the end of July.

on the top and then quotes the email he was sent.

During his vacation, he receives a call and he is told he has to urgently sent an email about some financial updates. He rushes to an internet cafe and sends the email. He makes a mistake though and mistypes one of the email addresses of the recipients. Instead of sending the email to “user@domain.com” he sends it at “usar@domain.com”.

His company’s SMTP server though receives the following error message from the remote SMTP server while trying to deliver the email:

<usar@domain.com>: host mx.domain.com[1.2.3.4] said: 550 5.1.1
   <usar@domain.com>... User unknown (in reply to RCPT TO command)

This means that his SMTP server will then send an email to him informing him about the error and quoting parts if not all of the email he had previously sent. The email will likely appear to be from “postmaster@company.com” or “do-not-reply@company.com” or something similar.
It will look like this:

This is the mail system at host mail.company.com.

I'm sorry to have to inform you that your message could not
be delivered to one or more recipients. It's attached below.

For further assistance, please send mail to postmaster.

If you do so, please include this problem report. You can
delete your own text from the attached returned message.

                  The mail system

<usar@domain.com>: host mx.domain.com[1.2.3.4] said: 550 5.1.1
   <usar@domain.com>... User unknown (in reply to RCPT TO command)
Reporting-MTA: dns; mail.company.com
X-Postfix-Queue-ID: AE4812AE328
X-Postfix-Sender: rfc822; employee1@company.com
Arrival-Date: Thu,  5 May 2011 20:05:27 +0200 (CEST)

Final-Recipient: rfc822; usar@domain.com
Original-Recipient: rfc822;usar@domain.com
Action: failed
Status: 5.1.1
Remote-MTA: dns; mx.domain.com
Diagnostic-Code: smtp; 550 5.1.1 <usar@domain.com>... User unknown

From: Loyal Employee <employee1@company.com>
Date: July 5, 2011 9:05:29 PM GMT+03:00
To: User User <usar@domain.com>
Subject: Re: Financial updates

Financial data goes here

But the user has still his vacation auto-reply turned on, so when the automatic postmaster’s email reaches his mailbox, the system will automatically reply back to the “postmaster@company.com” quoting the previous email and adding his auto-reply message:

Out of Office – I will be back from holidays at the end of July.

So the postmaster@company.com currently has all the financial details that he shouldn’t!

Apart from the fact that the user was sending financial data to somebody else in a clear text email instead of an encrypted one, the second biggest mistake that the user has made was that he has enabled vacation auto-replies that quote the email he was previously sent. That’s very very wrong. If you don’t want sensitive stuff ending at the postmaster’s inbox avoid quoting previous emails in your auto-replies by all means.

Based on a true story 🙂

please use indexes in your database tables

I don’t know how many times I’ve heard a sysadmin swearing at a web/application developer that has “forgotten” to add proper index to their database tables. Please dear developers, add those indexes, it’s not that hard!

Today I had to do it on a table for a xoops module. A single query could keep mysql very very busy…how busy ? the query could take more than 2 minutes, unless it was already cached! I’ll post the way I solved it as an example. It is actually usually quite easy to solve these kind of issues.

1) How to spot the problem
Your application is slow and your server’s “top” shows mysql running constantly at full load.

2) Find the problematic query. Login to mysql and run a ‘show processlist;’


mysql> show processlist;
+------+--------------+-----------+--------------------+---------+------+----------------+------------------------------------------------------------------------------------------------------+
| Id   | User         | Host      | db                 | Command | Time | State          | Info                                                                                                 |
+------+--------------+-----------+--------------------+---------+------+----------------+------------------------------------------------------------------------------------------------------+
| 1792 | admin        | localhost | aaa                | Sleep   |    0 |                | NULL                                                                                                 | 
| 4790 | user         | localhost | bbb                | Query   |    0 | Sorting result | SELECT * FROM foobar WHERE (com_rootid = '22797' AND com_id >= '22797') ORDER BY com_id              | 
| 4791 | user         | localhost | bbb                | Query   |    0 | Sorting result | SELECT * FROM foobar WHERE (com_rootid = '22797' AND com_id >= '22797') ORDER BY com_id              | 
| 4817 | admin        | localhost | NULL               | Query   |    0 | NULL           | show processlist                                                                                     | 
+------+--------------+-----------+--------------------+---------+------+----------------+------------------------------------------------------------------------------------------------------+
4 rows in set (0.00 sec)

3) Take a closer look at the structure of the table


mysql> describe foobar;
+--------------+-----------------------+------+-----+---------+----------------+
| Field        | Type                  | Null | Key | Default | Extra          |
+--------------+-----------------------+------+-----+---------+----------------+
| com_id       | mediumint(8) unsigned | NO   | PRI | NULL    | auto_increment | 
| com_pid      | mediumint(8) unsigned | NO   | MUL | 0       |                | 
| com_rootid   | mediumint(8) unsigned | NO   |     | 0       |                | 
| com_modid    | smallint(5) unsigned  | NO   |     | 0       |                | 
| com_itemid   | mediumint(8) unsigned | NO   | MUL | 0       |                | 
| com_icon     | varchar(25)           | NO   |     |         |                | 
| com_created  | int(10) unsigned      | NO   |     | 0       |                | 
| com_modified | int(10) unsigned      | NO   |     | 0       |                | 
| com_uid      | mediumint(8) unsigned | NO   | MUL | 0       |                | 
| com_ip       | varchar(15)           | NO   |     |         |                | 
| com_title    | varchar(255)          | NO   | MUL |         |                | 
| com_text     | text                  | NO   |     | NULL    |                | 
| com_sig      | tinyint(1) unsigned   | NO   |     | 0       |                | 
| com_status   | tinyint(1) unsigned   | NO   |     | 0       |                | 
| com_exparams | varchar(255)          | NO   |     |         |                | 
| dohtml       | tinyint(1) unsigned   | NO   |     | 0       |                | 
| dosmiley     | tinyint(1) unsigned   | NO   |     | 0       |                | 
| doxcode      | tinyint(1) unsigned   | NO   |     | 0       |                | 
| doimage      | tinyint(1) unsigned   | NO   |     | 0       |                | 
| dobr         | tinyint(1) unsigned   | NO   |     | 0       |                | 
+--------------+-----------------------+------+-----+---------+----------------+
20 rows in set (0.01 sec)

4) run EXPLAIN on the problematic query


mysql> explain SELECT * FROM foobar WHERE (com_rootid = '17536' AND com_id >= '17536') ORDER BY com_id;
+----+-------------+--------------------+------+-----------------------+------+---------+------+-------+-----------------------------+
| id | select_type | table              | type | possible_keys         | key  | key_len | ref  | rows  | Extra                       |
+----+-------------+--------------------+------+-----------------------+------+---------+------+-------+-----------------------------+
|  1 | SIMPLE      | foobar             | ALL  | PRIMARY               | NULL | NULL    | NULL | 18271 | Using where; Using filesort | 
+----+-------------+--------------------+------+-----------------------+------+---------+------+-------+-----------------------------+
1 row in set (0.02 sec)

If “type” is “ALL”, like the case above, then you have a problem. This is the worst “type” you could have. The query above scans the whole table and has to go through 18271 rows and then has to do a filesort on these rows.

5) Look at indexes, if there are any….


mysql> show index from foobar;
+--------------------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table              | Non_unique | Key_name   | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+--------------------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| foobar             |          0 | PRIMARY    |            1 | com_id      | A         |       18272 |     NULL | NULL   |      | BTREE      |         | 
| foobar             |          1 | com_pid    |            1 | com_pid     | A         |           1 |     NULL | NULL   |      | BTREE      |         | 
| foobar             |          1 | com_itemid |            1 | com_itemid  | A         |          18 |     NULL | NULL   |      | BTREE      |         | 
| foobar             |          1 | com_uid    |            1 | com_uid     | A         |           6 |     NULL | NULL   |      | BTREE      |         | 
| foobar             |          1 | com_title  |            1 | com_title   | A         |       18272 |       40 | NULL   |      | BTREE      |         | 
+--------------------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
5 rows in set (0.00 sec)

6)Create necessary new index


ALTER TABLE  `DB`.`foobar` ADD INDEX `com_id_rootid` (  `com_id` ,  `com_rootid` )

7) Explain the query again


mysql> explain SELECT * FROM foobar WHERE (com_rootid = '17536' AND com_id >= '17536') ORDER BY com_id;
+----+-------------+--------------------+------+------------------------+---------------+---------+-------+------+-----------------------------+
| id | select_type | table              | type | possible_keys          | key           | key_len | ref   | rows | Extra                       |
+----+-------------+--------------------+------+------------------------+---------------+---------+-------+------+-----------------------------+
|  1 | SIMPLE      | foobar             | ref  | PRIMARY,com_id_rootid  | com_id_rootid | 3       | const |    1 | Using where; Using filesort | 
+----+-------------+--------------------+------+------------------------+---------------+---------+-------+------+-----------------------------+
1 row in set (0.00 sec)

now the query is of type “ref” and it only fetches 1 row!
If the query could be optimized even more by the developer and he/she could replace ‘>=’ with ‘=’ then it would make us even happier


mysql> explain SELECT * FROM foobar WHERE (com_rootid = '17536' AND com_id = '17536') ORDER BY com_id;
+----+-------------+--------------------+-------+-----------------------+---------+---------+-------+------+-------+
| id | select_type | table              | type  | possible_keys         | key     | key_len | ref   | rows | Extra |
+----+-------------+--------------------+-------+-----------------------+---------+---------+-------+------+-------+
|  1 | SIMPLE      | foobar             | const | PRIMARY,com_id_rootid | PRIMARY | 3       | const |    1 |       | 
+----+-------------+--------------------+-------+-----------------------+---------+---------+-------+------+-------+
1 row in set (0.00 sec)

the type would now be ‘const’, which is the best type we could have.

The problem got fixed with just one command! Now the queries take milliseconds to finish and the web application is as fast as ever. The server load dropped from 2.5 to 0.4 with just this tiny addition to the indexes.

CPU load drops dramatically after adding the proper index to the table

CPU Load

So dear developers, please run EXPLAIN to your queries before you submit your applications and if you find queries with type=ALL try to add indexes! It saves all of us a loooooot of trouble!

For anyone who wants to read a nice blog post about EXPLAIN and what each part of the output means, I recommend that he/she reads this: MySQL Explain – Reference