Hundreds lines of log in wordpress show that, attackers are just trying passwords via xmlrpc.php
. Add protection using the WP fail2ban plugin, inspired by the post here.
Author: gonwan
Coroutines in C++/Boost
Starting with 1.56, boost/asio
provides asio::spawn()
to work with coroutines. Just paste the sample code here, with minor modifications:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
#include <boost/asio.hpp> #include <boost/asio/spawn.hpp> #include <boost/bind.hpp> #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> #include <iostream> using namespace std; using boost::asio::ip::tcp; class session: public boost::enable_shared_from_this<session> { public: explicit session(boost::asio::io_service &io_service) : socket_(io_service), timer_(io_service), strand_(io_service) { } tcp::socket &socket() { return socket_; } void go() { boost::asio::spawn(strand_, boost::bind(&session::echo, shared_from_this(), _1)); boost::asio::spawn(strand_, boost::bind(&session::timeout, shared_from_this(), _1)); } private: void echo(boost::asio::yield_context yield) { try { char data[128]; while (true) { timer_.expires_from_now(boost::posix_time::seconds(10)); size_t n = socket_.async_read_some(boost::asio::buffer(data), yield); boost::asio::async_write(socket_, boost::asio::buffer(data, n), yield); } } catch (exception &) { socket_.close(); timer_.cancel(); } } void timeout(boost::asio::yield_context yield) { while (socket_.is_open()) { boost::system::error_code ignored_ec; timer_.async_wait(yield[ignored_ec]); if (timer_.expires_from_now() <= boost::posix_time::seconds(0)) { socket_.close(); } } } tcp::socket socket_; boost::asio::deadline_timer timer_; boost::asio::io_service::strand strand_; }; void do_accept(boost::asio::io_service &io_service, unsigned short port, boost::asio::yield_context yield) { tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), port)); while (true) { boost::system::error_code ec; boost::shared_ptr<session> new_session(new session(io_service)); acceptor.async_accept(new_session->socket(), yield[ec]); if (!ec) { new_session->go(); } } } int main() { try { boost::asio::io_service io_service; boost::asio::spawn(io_service, boost::bind(do_accept, boost::ref(io_service), 2222, _1)); io_service.run(); } catch (exception &e) { cerr << "Exception: " << e.what() << endl; } return 0; } |
The Python in my previous article can be used to work with the code above. I also tried to write a TCP server with only boost::coroutines
classes. select()
is used, since I want the code to be platform independent. NOTE: with coroutines, we have only _one_ thread.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
#ifdef _WIN32 #include <winsock2.h> #include <ws2tcpip.h> #include <windows.h> #pragma comment(lib, "ws2_32.lib") #pragma warning(disable: 4996) #define sock_send(s, str, len) send(s, str, len, 0) #define sock_close(s) closesocket(s) #else #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> #define sock_send(s, str, len) send(s, str, len, MSG_NOSIGNAL) #define sock_close(s) close(s) #endif #include <cerrno> #include <cstdio> #include <cstring> #include <iostream> #include <list> #include <boost/bind.hpp> #include <boost/coroutine/all.hpp> #include <boost/shared_ptr.hpp> using namespace std; #ifdef _WIN32 struct Win32SocketWrapper { Win32SocketWrapper() { WSADATA wsaData; WSAStartup(0x0202, &wsaData); } ~Win32SocketWrapper() { WSACleanup(); } } g_win32_socket_wrapper; #endif class session { typedef boost::coroutines::symmetric_coroutine<void> coro_t; public: explicit session(int sock) : socket_(sock) { echo_coro_ = coro_t::call_type(boost::bind(&session::echo, this, _1)); } int socket() { return socket_; } void go() { echo_coro_(); } void echo(coro_t::yield_type &yield) { int rc; char buffer[128]; while (true) { memset(buffer, 0, sizeof(buffer)); yield(); rc = recv(socket_, buffer, sizeof(buffer), 0); if (rc == 0 || rc == -1) { /* close or error */ printf("socket[%d] closed, rc=%d..\n", socket_, rc); sock_close(socket_); socket_ = -1; /* do not release here, or the whole coroutine context will be invalid.. */ break; } else { sock_send(socket_, buffer, rc); } } } private: int socket_; coro_t::call_type echo_coro_; }; void event_loop(int server_sock) { list<boost::shared_ptr<session> > session_list; int rc, maxfd, client_sock; fd_set rdset; struct sockaddr_in client_addr; size_t addr_size = sizeof(struct sockaddr_in); while (true) { FD_ZERO(&rdset); FD_SET(server_sock, &rdset); maxfd = server_sock; list<boost::shared_ptr<session> >::iterator it = session_list.begin(); while (it != session_list.end()) { if ((*it)->socket() == -1) { session_list.erase(it++); } else { FD_SET((*it)->socket(), &rdset); if (maxfd < (*it)->socket()) { maxfd = (*it)->socket(); } ++it; } } /* max fd value plus 1 */ rc = select(maxfd+1, &rdset, 0, 0, NULL); if (rc == -1) { continue; } else { if (FD_ISSET(server_sock, &rdset)) { client_sock = (int)accept(server_sock, (struct sockaddr *)&client_addr, (socklen_t *)&addr_size); printf("socket[%d] accepted: %s:%d..\n", client_sock, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); boost::shared_ptr<session> new_session(new session(client_sock)); new_session->go(); /* go first */ session_list.push_back(new_session); } for (list<boost::shared_ptr<session> >::iterator it = session_list.begin(); it != session_list.end(); ++it) { if (FD_ISSET((*it)->socket(), &rdset)) { (*it)->go(); } } } } } int main() { int rc, server_sock; struct sockaddr_in server_addr; server_sock = (int)socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(2222); rc = bind(server_sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in)); if (rc < 0) { fprintf(stderr, "bind: %s.\n", strerror(errno)); return -1; } listen(server_sock, 5); /* loop */ event_loop(server_sock); sock_close(server_sock); return 0; } |
Coroutines in Python
Python 3.5 added native support for coroutines. Actually, there were several steps towards the current implementation. See Wikipedia, and it seems a bit messy to me:
- Python 2.5 implements better support for coroutine-like functionality, based on extended generators (PEP 342).
- Python 3.3 improves this ability, by supporting delegating to a subgenerator (PEP 380).
- Python 3.4 introduces a comprehensive asynchronous I/O framework as standardized in PEP 3156, which includes coroutines that leverage subgenerator delegation.
- Python 3.5 introduces explicit support for coroutines with async/await syntax (PEP 0492).
Before Python 2.5, there were only generators.
In Python 2.5, yield
was refined to be an expression rather than a statement, which gave the possibility to implement a simple coroutine. But still a lot of work left for programmers to use it. For instance, a simple conroutine scheduler was required.
In Python 3.3, yield from
was added to support subgenerators. Nothing to do with coroutines.
In Python 3.4, the Father of Python (Guido van Rossum) wrote a PEP himself to add an asyncio
module to simplify coroutine usage in Python. An official scheduler was added. We can use @asyncio.coroutine
to decorate a function. We can use yield from
expressions to yield to a specific coroutine.
In Python 3.5, async
/await
syntax was added, borrowed from C#. The newest PEP made coroutines a native Python language feature, and clearly separated them from generators. A native coroutine now declares with async def
syntax, and yield from
is replaced with await
expression. This removes generator/coroutine ambiguity. So in Python 3.5, coroutines used with asyncio
may be implemented using the async def
statement, or by using generators. Generator-based coroutines should be decorated with @asyncio.coroutine
, although this is not strictly enforced. The decorator enables compatibility with async def
coroutines, and also serves as documentation. See Python documents here.
The implementation can be found in this commit.
I wrote a echo server/client sample to try corutines. Server code first:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
#!/usr/bin/python3 import asyncio @asyncio.coroutine def start_server(): yield from asyncio.start_server(client_connected_handler, '127.0.0.1', 2222) @asyncio.coroutine def client_connected_handler(client_reader, client_writer): peer = client_writer.get_extra_info('peername') print('Connected..%s:%s' % (peer[0], peer[1])) while True: data = yield from client_reader.read(1024) if not data: print('Disconnected..%s:%s\n' % (peer[0], peer[1])) break print(data.decode(), end='') client_writer.write(data) loop = asyncio.get_event_loop() server = loop.run_until_complete(start_server()) try: loop.run_forever() except KeyboardInterrupt: pass server.close() loop.run_until_complete(server.wait_closed()) loop.close() |
Client code here, or you can simply use telnet
command:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#!/usr/bin/python3 import asyncio @asyncio.coroutine def tcp_echo_client(): reader, writer = yield from asyncio.open_connection('127.0.0.1', 2222) writer.write(b'first line\n') writer.write(b'second line\n') writer.write(b'third line\n') writer.write(b'EOF\n') print("Lines received..") while True: line = yield from reader.readline() if not line: break line = line.decode() print(line, end='') if line == 'EOF\n': break writer.close() loop = asyncio.get_event_loop() loop.run_until_complete(tcp_echo_client()) loop.close() |
Server output:
1 2 3 4 5 6 |
Connected..127.0.0.1:27643 first line second line third line EOF Disconnected..127.0.0.1:27643 |
Client output:
1 2 3 4 5 |
Lines received.. first line second line third line EOF |
With Python 3.5 on Ubuntu 16.04, we can also use async
/await
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
#!/usr/bin/python3 import asyncio async def start_server(): await asyncio.start_server(client_connected_handler, '127.0.0.1', 2222) async def client_connected_handler(client_reader, client_writer): peer = client_writer.get_extra_info('peername') print('Connected..%s:%s' % (peer[0], peer[1])) while True: data = await client_reader.read(1024) if not data: print('Disconnected..%s:%s\n' % (peer[0], peer[1])) break print(data.decode(), end='') client_writer.write(data) loop = asyncio.get_event_loop() server = loop.run_until_complete(start_server()) try: loop.run_forever() except KeyboardInterrupt: pass server.close() loop.run_until_complete(server.wait_closed()) loop.close() |
Basic Usage of Boost MultiIndex Containers
Just take a simple note here.
The Boost Multi-index Containers Library provides a class template named multi_index_container
which enables the construction of containers maintaining one or more indices with different sorting and access semantics.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
#include <string> #include <ostream> #include <boost/multi_index_container.hpp> #include <boost/multi_index/ordered_index.hpp> #include <boost/multi_index/identity.hpp> #include <boost/multi_index/member.hpp> #include <boost/multi_index/tag.hpp> #include <boost/lambda/lambda.hpp> using namespace std; using namespace boost::multi_index; struct auth { string m_name; string m_pass; auth(const string &name, const string &pass) : m_name(name), m_pass(pass) { } bool operator<(const auth &o) const { return m_name < o.m_name; } friend ostream &operator<<(ostream &os, const auth &a) { os << "(" << a.m_name << ", " << a.m_pass << ")"; return os; } }; struct employee { int m_id; auth m_auth; int m_hire; int m_resign; employee(int id, const string &name, const string &pass, int hire, int resign) : m_id(id), m_auth(name, pass), m_hire(hire), m_resign(resign) { } bool operator<(const employee &o) const { return m_id < o.m_id; } friend ostream &operator<<(ostream &os, const employee &e) { os << "(" << e.m_id << ", " << e.m_auth << ", " << e.m_hire << ", " << e.m_resign << ")"; return os; } }; struct auth_t { }; struct change_resign { int m_resign; change_resign(int r) : m_resign(r) { } void operator()(employee &e) { e.m_resign = m_resign; } }; typedef multi_index_container< employee, indexed_by< /* sort by employee::operator< */ ordered_unique<identity<employee> >, /* sort by less<int> on m_hire */ ordered_non_unique<member<employee, int, &employee::m_hire> >, /* sort by less<auth> on m_auth */ ordered_non_unique<tag<auth_t>, member<employee, auth, &employee::m_auth> > > > employee_set; int main() { employee_set es; es.insert(employee(1, "555", "555pass", 2012, 0)); es.insert(employee(2, "444", "444pass", 2011, 0)); es.insert(employee(3, "333", "333pass", 2013, 0)); es.insert(employee(4, "222", "222pass", 2015, 0)); es.insert(employee(5, "555", "555pass", 2014, 0)); /* dup */ typedef employee_set::nth_index<1>::type hire_index_t; typedef employee_set::index<auth_t>::type auth_index_t; cout << "Get a view to index #1 (m_hire).." << endl; hire_index_t &hire_index = es.get<1>(); std::copy(hire_index.begin(), hire_index.end(), ostream_iterator<employee>(cout, "\n")); cout << "Get a view to index tag auth_t (m_auth).." << endl; const auth_index_t &auth_index = es.get<auth_t>(); std::copy(auth_index.begin(), auth_index.end(), ostream_iterator<employee>(cout, "\n")); cout << "Find.." << endl; hire_index_t::iterator it = hire_index.find(2015); #if 0 employee t = *it; t.m_resign = 2048; hire_index.replace(it, t); #else hire_index.modify_key(it, boost::lambda::_1=1111); int old_resign = it->m_resign; hire_index.modify(it, change_resign(2048), change_resign(old_resign)); #endif cout << (*it) << endl; cout << "Find all.." << endl; pair<auth_index_t::const_iterator, auth_index_t::const_iterator> pr = auth_index.equal_range(auth("555", "")); std::copy(pr.first, pr.second, ostream_iterator<employee>(cout, "\n")); return 0; } |
Output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
Get a view to index #1 (m_hire).. (2, (444, 444pass), 2011, 0) (1, (555, 555pass), 2012, 0) (3, (333, 333pass), 2013, 0) (5, (555, 555pass), 2014, 0) (4, (222, 222pass), 2015, 0) Get a view to index tag auth_t (m_auth).. (4, (222, 222pass), 2015, 0) (3, (333, 333pass), 2013, 0) (2, (444, 444pass), 2011, 0) (1, (555, 555pass), 2012, 0) (5, (555, 555pass), 2014, 0) Find.. (4, (222, 222pass), 1111, 2048) Find all.. (1, (555, 555pass), 2012, 0) (5, (555, 555pass), 2014, 0) |
To use with pointer values, only limited change needed as highlighted:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
#include <string> #include <ostream> #include <boost/multi_index_container.hpp> #include <boost/multi_index/ordered_index.hpp> #include <boost/multi_index/identity.hpp> #include <boost/multi_index/member.hpp> #include <boost/multi_index/tag.hpp> #include <boost/lambda/lambda.hpp> using namespace std; using namespace boost::multi_index; struct auth { string m_name; string m_pass; auth(const string &name, const string &pass) : m_name(name), m_pass(pass) { } bool operator<(const auth &o) const { return m_name < o.m_name; } friend ostream &operator<<(ostream &os, const auth &a) { os << "(" << a.m_name << ", " << a.m_pass << ")"; return os; } }; struct employee { int m_id; auth m_auth; int m_hire; int m_resign; employee(int id, const string &name, const string &pass, int hire, int resign) : m_id(id), m_auth(name, pass), m_hire(hire), m_resign(resign) { } bool operator<(const employee &o) const { return m_id < o.m_id; } friend ostream &operator<<(ostream &os, const employee *e) { os << "(" << e->m_id << ", " << e->m_auth << ", " << e->m_hire << ", " << e->m_resign << ")"; return os; } }; struct auth_t { }; struct change_resign { int m_resign; change_resign(int r) : m_resign(r) { } void operator()(employee *e) { e->m_resign = m_resign; } }; typedef multi_index_container< employee *, indexed_by< /* sort by employee::operator< */ ordered_unique<identity<employee> >, /* sort by less<int> on m_hire */ ordered_non_unique<member<employee, int, &employee::m_hire> >, /* sort by less<auth> on m_auth */ ordered_non_unique<tag<auth_t>, member<employee, auth, &employee::m_auth> > > > employee_set; int main() { employee_set es; es.insert(new employee(1, "555", "555pass", 2012, 0)); es.insert(new employee(2, "444", "444pass", 2011, 0)); es.insert(new employee(3, "333", "333pass", 2013, 0)); es.insert(new employee(4, "222", "222pass", 2015, 0)); es.insert(new employee(5, "555", "555pass", 2014, 0)); /* dup */ typedef employee_set::nth_index<1>::type hire_index_t; typedef employee_set::index<auth_t>::type auth_index_t; cout << "Get a view to index #1 (m_hire).." << endl; hire_index_t &hire_index = es.get<1>(); std::copy(hire_index.begin(), hire_index.end(), ostream_iterator<employee *>(cout, "\n")); cout << "Get a view to index tag auth_t (m_auth).." << endl; const auth_index_t &auth_index = es.get<auth_t>(); std::copy(auth_index.begin(), auth_index.end(), ostream_iterator<employee *>(cout, "\n")); cout << "Find.." << endl; hire_index_t::iterator it = hire_index.find(2015); #if 0 employee *t = *it; t->m_auth.m_name = "888"; /* must use replace() to notify changes in indexed fields */ hire_index.replace(it, t); #else hire_index.modify_key(it, boost::lambda::_1=1111); int old_resign = (*it)->m_resign; hire_index.modify(it, change_resign(2048), change_resign(old_resign)); #endif cout << (*it) << endl; cout << "Find all.." << endl; pair<auth_index_t::const_iterator, auth_index_t::const_iterator> pr = auth_index.equal_range(auth("555", "")); std::copy(pr.first, pr.second, ostream_iterator<employee *>(cout, "\n")); /* clear */ for (employee_set::const_iterator it = es.begin(); it != es.end(); ++it) { delete *it; } employee_set().swap(es); return 0; } |
Enabing Pretty Permalinks
Well.. long time no see. Just have some time to optimize the site for better analysis.
According to the official tutorial:
1. Enable mod_rewrite
in apache2.
1 |
# sudo a2enmod rewrite |
2. Enable FollowSymLinks
option, which is default.
3. Enable FileInfo
directives. Edit /etc/apache2/sites-available/yoursite.com.conf
, add:
1 2 3 4 |
<Directory /home/yourname/yoursite/> Require all granted AllowOverride FileInfo </Directory> |
4. Restart apache:
1 |
# sudo service apache2 restart |
Updated Dec 31, 2015:
Enabling mod_rewrite
rewrites all requests including the one used by mod_status
. To disable this, add a rule to the .htaccess
file.
1 |
RewriteCond %{REQUEST_URI} !=/server-status |
Then, change its user & group attributes to prevent overwriting from apache.