読者です 読者をやめる 読者になる 読者になる

臥薪嘗胆

インフラエンジニアのあれこれ

Cやってみよう #6

前年の続き

だいぶ間が空いてしまった。
2016年、restartです。
続けるように。

mod_vhost_maxclients.c のソースを見ていきましょう。

174   for (i = 0; i < vhost_maxclients_server_limit; ++i) {
175     for (j = 0; j < vhost_maxclients_thread_limit; ++j) {
176       worker_score *ws_record = ap_get_scoreboard_worker(i, j);
177 #ifdef __APACHE24__
178       char *client_ip = r->connection->client_ip;
179 #else
180       char *client_ip = r->connection->remote_ip;
181 #endif
  • 174行目は vhost_maxclients_server_limit まで繰り返しの処理が開始
  • 175行目は vhost_maxclients_thread_limit まで繰り返しの処理が開始
    • 例えば両方のlimitの値が10の場合は、10*10=100回、繰り返すわけですね。
  • 176行目が肝のようだ。
    ap_get_scoreboard_worker この処理で、apacheが持つscoreboardから値を取って
    *ws_record に値を入れている。
    http://apache.org/server-status
    ↑のserver-statusをimageしとけばいいのだろうか。
  • 178,180行目は、接続元のIPを取得している。
183       switch (ws_record->status) {
184          case SERVER_BUSY_READ:
185          case SERVER_BUSY_WRITE:
186          case SERVER_BUSY_KEEPALIVE:
187          case SERVER_BUSY_LOG:
188          case SERVER_BUSY_DNS:
189          case SERVER_CLOSING:
190          case SERVER_GRACEFUL:
  • ws_record->status のstatusで分岐をおこない、以下の状態の時にカウントをしている
#define SERVER_BUSY_READ 3  /* Reading a client request */
#define SERVER_BUSY_WRITE 4 /* Processing a client request */
#define SERVER_BUSY_KEEPALIVE 5 /* Waiting for more requests via keepalive */
#define SERVER_BUSY_LOG 6   /* Logging the request */
#define SERVER_BUSY_DNS 7   /* Looking up a hostname */
#define SERVER_CLOSING 8    /* Closing the connection */
#define SERVER_GRACEFUL 9   /* server is gracefully finishing request */

ここからが本題なのです。

190       case SERVER_GRACEFUL:
191         /* check maxclients per vhost */
192         if (strcmp(vhostport, ws_record->vhost) == 0) {
193           vhost_count++;
194           ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, "DEBUG: (increment %s): %d/%d", vhostport,
195                        vhost_count, scfg->vhost_maxclients);
196           if (vhost_count > scfg->vhost_maxclients) {
197             if (scfg->dryrun > 0) {
198               ap_log_error(
199                   APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
200                   "NOTICE: [DRY-RUN] [VHOST_COUNT] return 503 from %s : %d / %d client_ip: %s uri: %s filename: %s",
201                   vhostport, vhost_count, scfg->vhost_maxclients, client_ip, r->uri, r->filename);
202             } else {
203               ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
204                            "NOTICE: [VHOST_COUNT] return 503 from %s : %d / %d client_ip: %s uri: %s filename: %s",
205                            vhostport, vhost_count, scfg->vhost_maxclients, client_ip, r->uri, r->filename);
206             }
207             return (scfg->dryrun > 0) ? DECLINED : HTTP_SERVICE_UNAVAILABLE;
208           }
209
210           /* check maxclients per ip in same vhost */
211           if (scfg->vhost_maxclients_per_ip > 0) {
212             if (strcmp(client_ip, ws_record->client) == 0) {
213               ip_count++;
214               if (ip_count > scfg->vhost_maxclients_per_ip) {
215                 if (scfg->dryrun > 0) {
216                   ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, "NOTICE: [DRY-RUN] [CLIENT_COUNT] return "
217                                                                             "503 from %s : %d / %d client_ip: %s uri: "
218                                                                             "%s filename: %s",
219                                vhostport, ip_count, scfg->vhost_maxclients_per_ip, client_ip, r->uri, r->filename);
220                 } else {
221                   ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf,
222                                "NOTICE: [CLIENT_COUNT] return 503 from %s : %d / %d client_ip: %s uri: %s filename: %s",
223                                vhostport, ip_count, scfg->vhost_maxclients_per_ip, client_ip, r->uri, r->filename);
224                 }
225                 return (scfg->dryrun > 0) ? DECLINED : HTTP_SERVICE_UNAVAILABLE;
226               }
227             }
228           }
229         }
230         break;
  • 192行目でリクエストの hoge.com:80 とscoreboardとが一致していれば vhost_count++ をインクリメント。
  • 196行目で設定されているlimit値を超えているかの判定を行っている。
    超えている場合、以下の処理を行う

    • 197行目でドライランかの判定を行い、それぞれでログを出力している
    • 207行目でドライランであれば DECLINED
      ドライランでなければ、 HTTP_SERVICE_UNAVAILABLE = 503 となる
  • 211行目移行は、同一のvhostに対して同じIPからのアクセスを制御する

こんな感じで、このモジュールは書かれていることが分かった。

一旦、おわりー

Cも時間を割けばわかるものなのですね。。 つぎは何しよう。