Annotation of embedaddon/nginx/src/http/modules/ngx_http_realip_module.c, revision 1.1
1.1 ! misho 1:
! 2: /*
! 3: * Copyright (C) Igor Sysoev
! 4: * Copyright (C) Nginx, Inc.
! 5: */
! 6:
! 7:
! 8: #include <ngx_config.h>
! 9: #include <ngx_core.h>
! 10: #include <ngx_http.h>
! 11:
! 12:
! 13: #define NGX_HTTP_REALIP_XREALIP 0
! 14: #define NGX_HTTP_REALIP_XFWD 1
! 15: #define NGX_HTTP_REALIP_HEADER 2
! 16:
! 17:
! 18: typedef struct {
! 19: ngx_array_t *from; /* array of ngx_cidr_t */
! 20: ngx_uint_t type;
! 21: ngx_uint_t hash;
! 22: ngx_str_t header;
! 23: ngx_flag_t recursive;
! 24: } ngx_http_realip_loc_conf_t;
! 25:
! 26:
! 27: typedef struct {
! 28: ngx_connection_t *connection;
! 29: struct sockaddr *sockaddr;
! 30: socklen_t socklen;
! 31: ngx_str_t addr_text;
! 32: } ngx_http_realip_ctx_t;
! 33:
! 34:
! 35: static ngx_int_t ngx_http_realip_handler(ngx_http_request_t *r);
! 36: static ngx_int_t ngx_http_realip_set_addr(ngx_http_request_t *r,
! 37: ngx_addr_t *addr);
! 38: static void ngx_http_realip_cleanup(void *data);
! 39: static char *ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd,
! 40: void *conf);
! 41: static char *ngx_http_realip(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
! 42: static void *ngx_http_realip_create_loc_conf(ngx_conf_t *cf);
! 43: static char *ngx_http_realip_merge_loc_conf(ngx_conf_t *cf,
! 44: void *parent, void *child);
! 45: static ngx_int_t ngx_http_realip_init(ngx_conf_t *cf);
! 46:
! 47:
! 48: static ngx_command_t ngx_http_realip_commands[] = {
! 49:
! 50: { ngx_string("set_real_ip_from"),
! 51: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 52: ngx_http_realip_from,
! 53: NGX_HTTP_LOC_CONF_OFFSET,
! 54: 0,
! 55: NULL },
! 56:
! 57: { ngx_string("real_ip_header"),
! 58: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 59: ngx_http_realip,
! 60: NGX_HTTP_LOC_CONF_OFFSET,
! 61: 0,
! 62: NULL },
! 63:
! 64: { ngx_string("real_ip_recursive"),
! 65: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
! 66: ngx_conf_set_flag_slot,
! 67: NGX_HTTP_LOC_CONF_OFFSET,
! 68: offsetof(ngx_http_realip_loc_conf_t, recursive),
! 69: NULL },
! 70:
! 71: ngx_null_command
! 72: };
! 73:
! 74:
! 75:
! 76: static ngx_http_module_t ngx_http_realip_module_ctx = {
! 77: NULL, /* preconfiguration */
! 78: ngx_http_realip_init, /* postconfiguration */
! 79:
! 80: NULL, /* create main configuration */
! 81: NULL, /* init main configuration */
! 82:
! 83: NULL, /* create server configuration */
! 84: NULL, /* merge server configuration */
! 85:
! 86: ngx_http_realip_create_loc_conf, /* create location configuration */
! 87: ngx_http_realip_merge_loc_conf /* merge location configuration */
! 88: };
! 89:
! 90:
! 91: ngx_module_t ngx_http_realip_module = {
! 92: NGX_MODULE_V1,
! 93: &ngx_http_realip_module_ctx, /* module context */
! 94: ngx_http_realip_commands, /* module directives */
! 95: NGX_HTTP_MODULE, /* module type */
! 96: NULL, /* init master */
! 97: NULL, /* init module */
! 98: NULL, /* init process */
! 99: NULL, /* init thread */
! 100: NULL, /* exit thread */
! 101: NULL, /* exit process */
! 102: NULL, /* exit master */
! 103: NGX_MODULE_V1_PADDING
! 104: };
! 105:
! 106:
! 107: static ngx_int_t
! 108: ngx_http_realip_handler(ngx_http_request_t *r)
! 109: {
! 110: u_char *p;
! 111: size_t len;
! 112: ngx_str_t *value;
! 113: ngx_uint_t i, hash;
! 114: ngx_addr_t addr;
! 115: ngx_array_t *xfwd;
! 116: ngx_list_part_t *part;
! 117: ngx_table_elt_t *header;
! 118: ngx_connection_t *c;
! 119: ngx_http_realip_ctx_t *ctx;
! 120: ngx_http_realip_loc_conf_t *rlcf;
! 121:
! 122: ctx = ngx_http_get_module_ctx(r, ngx_http_realip_module);
! 123:
! 124: if (ctx) {
! 125: return NGX_DECLINED;
! 126: }
! 127:
! 128: rlcf = ngx_http_get_module_loc_conf(r, ngx_http_realip_module);
! 129:
! 130: if (rlcf->from == NULL) {
! 131: return NGX_DECLINED;
! 132: }
! 133:
! 134: switch (rlcf->type) {
! 135:
! 136: case NGX_HTTP_REALIP_XREALIP:
! 137:
! 138: if (r->headers_in.x_real_ip == NULL) {
! 139: return NGX_DECLINED;
! 140: }
! 141:
! 142: value = &r->headers_in.x_real_ip->value;
! 143: xfwd = NULL;
! 144:
! 145: break;
! 146:
! 147: case NGX_HTTP_REALIP_XFWD:
! 148:
! 149: xfwd = &r->headers_in.x_forwarded_for;
! 150:
! 151: if (xfwd->elts == NULL) {
! 152: return NGX_DECLINED;
! 153: }
! 154:
! 155: value = NULL;
! 156:
! 157: break;
! 158:
! 159: default: /* NGX_HTTP_REALIP_HEADER */
! 160:
! 161: part = &r->headers_in.headers.part;
! 162: header = part->elts;
! 163:
! 164: hash = rlcf->hash;
! 165: len = rlcf->header.len;
! 166: p = rlcf->header.data;
! 167:
! 168: for (i = 0; /* void */ ; i++) {
! 169:
! 170: if (i >= part->nelts) {
! 171: if (part->next == NULL) {
! 172: break;
! 173: }
! 174:
! 175: part = part->next;
! 176: header = part->elts;
! 177: i = 0;
! 178: }
! 179:
! 180: if (hash == header[i].hash
! 181: && len == header[i].key.len
! 182: && ngx_strncmp(p, header[i].lowcase_key, len) == 0)
! 183: {
! 184: value = &header[i].value;
! 185: xfwd = NULL;
! 186:
! 187: goto found;
! 188: }
! 189: }
! 190:
! 191: return NGX_DECLINED;
! 192: }
! 193:
! 194: found:
! 195:
! 196: c = r->connection;
! 197:
! 198: addr.sockaddr = c->sockaddr;
! 199: addr.socklen = c->socklen;
! 200: /* addr.name = c->addr_text; */
! 201:
! 202: if (ngx_http_get_forwarded_addr(r, &addr, xfwd, value, rlcf->from,
! 203: rlcf->recursive)
! 204: != NGX_DECLINED)
! 205: {
! 206: return ngx_http_realip_set_addr(r, &addr);
! 207: }
! 208:
! 209: return NGX_DECLINED;
! 210: }
! 211:
! 212:
! 213: static ngx_int_t
! 214: ngx_http_realip_set_addr(ngx_http_request_t *r, ngx_addr_t *addr)
! 215: {
! 216: size_t len;
! 217: u_char *p;
! 218: u_char text[NGX_SOCKADDR_STRLEN];
! 219: ngx_connection_t *c;
! 220: ngx_pool_cleanup_t *cln;
! 221: ngx_http_realip_ctx_t *ctx;
! 222:
! 223: cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_realip_ctx_t));
! 224: if (cln == NULL) {
! 225: return NGX_HTTP_INTERNAL_SERVER_ERROR;
! 226: }
! 227:
! 228: ctx = cln->data;
! 229: ngx_http_set_ctx(r, ctx, ngx_http_realip_module);
! 230:
! 231: c = r->connection;
! 232:
! 233: len = ngx_sock_ntop(addr->sockaddr, text, NGX_SOCKADDR_STRLEN, 0);
! 234: if (len == 0) {
! 235: return NGX_HTTP_INTERNAL_SERVER_ERROR;
! 236: }
! 237:
! 238: p = ngx_pnalloc(c->pool, len);
! 239: if (p == NULL) {
! 240: return NGX_HTTP_INTERNAL_SERVER_ERROR;
! 241: }
! 242:
! 243: ngx_memcpy(p, text, len);
! 244:
! 245: cln->handler = ngx_http_realip_cleanup;
! 246:
! 247: ctx->connection = c;
! 248: ctx->sockaddr = c->sockaddr;
! 249: ctx->socklen = c->socklen;
! 250: ctx->addr_text = c->addr_text;
! 251:
! 252: c->sockaddr = addr->sockaddr;
! 253: c->socklen = addr->socklen;
! 254: c->addr_text.len = len;
! 255: c->addr_text.data = p;
! 256:
! 257: return NGX_DECLINED;
! 258: }
! 259:
! 260:
! 261: static void
! 262: ngx_http_realip_cleanup(void *data)
! 263: {
! 264: ngx_http_realip_ctx_t *ctx = data;
! 265:
! 266: ngx_connection_t *c;
! 267:
! 268: c = ctx->connection;
! 269:
! 270: c->sockaddr = ctx->sockaddr;
! 271: c->socklen = ctx->socklen;
! 272: c->addr_text = ctx->addr_text;
! 273: }
! 274:
! 275:
! 276: static char *
! 277: ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
! 278: {
! 279: ngx_http_realip_loc_conf_t *rlcf = conf;
! 280:
! 281: ngx_int_t rc;
! 282: ngx_str_t *value;
! 283: ngx_cidr_t *cidr;
! 284:
! 285: value = cf->args->elts;
! 286:
! 287: if (rlcf->from == NULL) {
! 288: rlcf->from = ngx_array_create(cf->pool, 2,
! 289: sizeof(ngx_cidr_t));
! 290: if (rlcf->from == NULL) {
! 291: return NGX_CONF_ERROR;
! 292: }
! 293: }
! 294:
! 295: cidr = ngx_array_push(rlcf->from);
! 296: if (cidr == NULL) {
! 297: return NGX_CONF_ERROR;
! 298: }
! 299:
! 300: #if (NGX_HAVE_UNIX_DOMAIN)
! 301:
! 302: if (ngx_strcmp(value[1].data, "unix:") == 0) {
! 303: cidr->family = AF_UNIX;
! 304: return NGX_CONF_OK;
! 305: }
! 306:
! 307: #endif
! 308:
! 309: rc = ngx_ptocidr(&value[1], cidr);
! 310:
! 311: if (rc == NGX_ERROR) {
! 312: ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"",
! 313: &value[1]);
! 314: return NGX_CONF_ERROR;
! 315: }
! 316:
! 317: if (rc == NGX_DONE) {
! 318: ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
! 319: "low address bits of %V are meaningless", &value[1]);
! 320: }
! 321:
! 322: return NGX_CONF_OK;
! 323: }
! 324:
! 325:
! 326: static char *
! 327: ngx_http_realip(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
! 328: {
! 329: ngx_http_realip_loc_conf_t *rlcf = conf;
! 330:
! 331: ngx_str_t *value;
! 332:
! 333: value = cf->args->elts;
! 334:
! 335: if (ngx_strcmp(value[1].data, "X-Real-IP") == 0) {
! 336: rlcf->type = NGX_HTTP_REALIP_XREALIP;
! 337: return NGX_CONF_OK;
! 338: }
! 339:
! 340: if (ngx_strcmp(value[1].data, "X-Forwarded-For") == 0) {
! 341: rlcf->type = NGX_HTTP_REALIP_XFWD;
! 342: return NGX_CONF_OK;
! 343: }
! 344:
! 345: rlcf->type = NGX_HTTP_REALIP_HEADER;
! 346: rlcf->hash = ngx_hash_strlow(value[1].data, value[1].data, value[1].len);
! 347: rlcf->header = value[1];
! 348:
! 349: return NGX_CONF_OK;
! 350: }
! 351:
! 352:
! 353: static void *
! 354: ngx_http_realip_create_loc_conf(ngx_conf_t *cf)
! 355: {
! 356: ngx_http_realip_loc_conf_t *conf;
! 357:
! 358: conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_realip_loc_conf_t));
! 359: if (conf == NULL) {
! 360: return NULL;
! 361: }
! 362:
! 363: /*
! 364: * set by ngx_pcalloc():
! 365: *
! 366: * conf->from = NULL;
! 367: * conf->hash = 0;
! 368: * conf->header = { 0, NULL };
! 369: */
! 370:
! 371: conf->type = NGX_CONF_UNSET_UINT;
! 372: conf->recursive = NGX_CONF_UNSET;
! 373:
! 374: return conf;
! 375: }
! 376:
! 377:
! 378: static char *
! 379: ngx_http_realip_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
! 380: {
! 381: ngx_http_realip_loc_conf_t *prev = parent;
! 382: ngx_http_realip_loc_conf_t *conf = child;
! 383:
! 384: if (conf->from == NULL) {
! 385: conf->from = prev->from;
! 386: }
! 387:
! 388: ngx_conf_merge_uint_value(conf->type, prev->type, NGX_HTTP_REALIP_XREALIP);
! 389: ngx_conf_merge_value(conf->recursive, prev->recursive, 0);
! 390:
! 391: if (conf->header.len == 0) {
! 392: conf->hash = prev->hash;
! 393: conf->header = prev->header;
! 394: }
! 395:
! 396: return NGX_CONF_OK;
! 397: }
! 398:
! 399:
! 400: static ngx_int_t
! 401: ngx_http_realip_init(ngx_conf_t *cf)
! 402: {
! 403: ngx_http_handler_pt *h;
! 404: ngx_http_core_main_conf_t *cmcf;
! 405:
! 406: cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
! 407:
! 408: h = ngx_array_push(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers);
! 409: if (h == NULL) {
! 410: return NGX_ERROR;
! 411: }
! 412:
! 413: *h = ngx_http_realip_handler;
! 414:
! 415: h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers);
! 416: if (h == NULL) {
! 417: return NGX_ERROR;
! 418: }
! 419:
! 420: *h = ngx_http_realip_handler;
! 421:
! 422: return NGX_OK;
! 423: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>