ngx_int_t ngx_http_set_misc_set_decode_hex(ngx_http_request_t *r, ngx_str_t *res, ngx_http_variable_value_t *v) { u_char *p; ngx_int_t n; ngx_int_t i; if (v->len % 2 != 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "set_decode_hex: invalid value"); return NGX_ERROR; } p = v->data; ndk_palloc_re(res->data, r->pool, v->len/2); for (i = 0; i < v->len/2; i++) { n = ngx_hextoi(p, 2); if (n == NGX_ERROR || n > 255) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "set_decode_hex: invalid value"); return NGX_ERROR; } p += 2; res->data[i] = (u_char) n; } res->len = v->len/2; return NGX_OK; }
static ngx_int_t ngx_let_toi(ngx_str_t* s) { return (s->len > 2 && s->data[0] == '0' && s->data[1] == 'x') ? ngx_hextoi(s->data + 2, s->len - 2) : ngx_atoi(s->data, s->len); }
/* * 添加cache文件到file_cache中 * 参数: name是完整文件名称 */ static ngx_int_t ngx_http_file_cache_add_file(ngx_tree_ctx_t *ctx, ngx_str_t *name) { u_char *p; ngx_int_t n; ngx_uint_t i; ngx_http_cache_t c; ngx_http_file_cache_t *cache; // 因为name是文件的完整路径名称,不应该仅是文件名的长度 if (name->len < 2 * NGX_HTTP_CACHE_KEY_LEN) { return NGX_ERROR; } // 检查cache文件大小,cache文件中存放的内容至少包含file_cache_header_t结构大小 if (ctx->size < (off_t) sizeof(ngx_http_file_cache_header_t)) { ngx_log_error(NGX_LOG_CRIT, ctx->log, 0, "cache file \"%s\" is too small", name->data); return NGX_ERROR; } ngx_memzero(&c, sizeof(ngx_http_cache_t)); cache = ctx->data; c.length = ctx->size; // ??? c.fs_size = (ctx->fs_size + cache->bsize - 1) / cache->bsize; // ??? // 将HEX格式的文件名转换为整数形式存放于 c.key 数组中 p = &name->data[name->len - 2 * NGX_HTTP_CACHE_KEY_LEN]; for (i = 0; i < NGX_HTTP_CACHE_KEY_LEN; i++) { n = ngx_hextoi(p, 2); if (n == NGX_ERROR) { return NGX_ERROR; } p += 2; c.key[i] = (u_char) n; } return ngx_http_file_cache_add(cache, &c); }
ngx_int_t ngx_http_qrcode_set_bg_color(ngx_http_request_t *r, ngx_int_t *color, ngx_array_t *compiled_args) { ngx_str_t *arg; ngx_int_t i; arg = compiled_args->elts; if (arg[0].len != 6) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "bg_color format error, it should be like FF00FF. error value %V", arg); return NGX_ERROR; } for (i = 0; i < 3; i++) { *(color + i) = ngx_hextoi(arg[0].data + i*2, 2); } return NGX_OK; }
static ngx_int_t ngx_http_file_cache_add_file(ngx_tree_ctx_t *ctx, ngx_str_t *name) { u_char *p; ngx_int_t n; ngx_uint_t i; ngx_http_cache_t c; ngx_http_file_cache_t *cache; if (name->len < 2 * NGX_HTTP_CACHE_KEY_LEN) { return NGX_ERROR; } if (ctx->size < (off_t) sizeof(ngx_http_file_cache_header_t)) { ngx_log_error(NGX_LOG_CRIT, ctx->log, 0, "cache file \"%s\" is too small", name->data); return NGX_ERROR; } ngx_memzero(&c, sizeof(ngx_http_cache_t)); cache = ctx->data; c.length = ctx->size; c.fs_size = (ctx->fs_size + cache->bsize - 1) / cache->bsize; p = &name->data[name->len - 2 * NGX_HTTP_CACHE_KEY_LEN]; for (i = 0; i < NGX_HTTP_CACHE_KEY_LEN; i++) { n = ngx_hextoi(p, 2); if (n == NGX_ERROR) { return NGX_ERROR; } p += 2; c.key[i] = (u_char) n; } return ngx_http_file_cache_add(cache, &c); }
ngx_int_t ngx_http_set_misc_set_decode_hex(ngx_http_request_t *r, ngx_str_t *res, ngx_http_variable_value_t *v) { u_char *p; ngx_int_t n; ngx_uint_t i; size_t len; if (v->len % 2 != 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "set_decode_hex: invalid value"); return NGX_ERROR; } p = v->data; len = v->len >> 1; res->data = ngx_palloc(r->pool, len); if (res->data == NULL) { return NGX_ERROR; } for (i = 0; i < len; i++) { n = ngx_hextoi(p, 2); if (n == NGX_ERROR || n > 255) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "set_decode_hex: invalid value"); return NGX_ERROR; } p += 2; res->data[i] = (u_char) n; } res->len = len; return NGX_OK; }
static ngx_int_t ngx_http_file_cache_add_file(ngx_tree_ctx_t *ctx, ngx_str_t *name) { u_char *p; ngx_fd_t fd; ngx_int_t n; ngx_uint_t i; ngx_file_info_t fi; ngx_http_cache_t c; ngx_http_file_cache_t *cache; ngx_http_file_cache_header_t h; if (name->len < 2 * NGX_HTTP_CACHE_KEY_LEN) { return NGX_ERROR; } ngx_memzero(&c, sizeof(ngx_http_cache_t)); fd = ngx_open_file(name->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); if (fd == NGX_INVALID_FILE) { ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, ngx_open_file_n " \"%s\" failed", name->data); return NGX_ERROR; } c.file.fd = fd; c.file.name = *name; c.file.log = ctx->log; n = ngx_read_file(&c.file, (u_char *) &h, sizeof(ngx_http_file_cache_header_t), 0); if (n == NGX_ERROR) { return NGX_ERROR; } if ((size_t) n < sizeof(ngx_http_file_cache_header_t)) { ngx_log_error(NGX_LOG_CRIT, ctx->log, 0, "cache file \"%s\" is too small", name->data); return NGX_ERROR; } if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, ngx_fd_info_n " \"%s\" failed", name->data); } else { c.uniq = ngx_file_uniq(&fi); c.valid_sec = h.valid_sec; c.valid_msec = h.valid_msec; c.body_start = h.body_start; c.length = ngx_file_size(&fi); } if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, ngx_close_file_n " \"%s\" failed", name->data); } if (c.body_start == 0) { return NGX_ERROR; } p = &name->data[name->len - 2 * NGX_HTTP_CACHE_KEY_LEN]; for (i = 0; i < NGX_HTTP_CACHE_KEY_LEN; i++) { n = ngx_hextoi(p, 2); if (n == NGX_ERROR) { return NGX_ERROR; } p += 2; c.key[i] = (u_char) n; } cache = ctx->data; return ngx_http_file_cache_add(cache, &c); }
static ngx_int_t ngx_http_secure_link_old_variable(ngx_http_request_t *r, ngx_http_secure_link_conf_t *conf, ngx_http_variable_value_t *v, uintptr_t data) { u_char *p, *start, *end, *last; size_t len; ngx_int_t n; ngx_uint_t i; ngx_md5_t md5; u_char hash[16]; p = &r->unparsed_uri.data[1]; last = r->unparsed_uri.data + r->unparsed_uri.len; // 获取/p/5e814704a28d9bc1914ff19fa0c4a00a/link/xx请求中5e814704a28d9bc1914ff19fa0c4a00a字符串 while (p < last) { if (*p++ == '/') { start = p; goto md5_start; } } goto not_found; md5_start: // 获取/p/5e814704a28d9bc1914ff19fa0c4a00a/link/xx请求中/link/xx字符串做为新的uri while (p < last) { if (*p++ == '/') { end = p - 1; goto url_start; } } goto not_found; url_start: len = last - p; //5e814704a28d9bc1914ff19fa0c4a00a必须满足32字节,因为MD5运算结果是32字节 if (end - start != 32 || len == 0) { goto not_found; } //计算secure_link_secret配置的字符串的MD5校验值 ngx_md5_init(&md5); ngx_md5_update(&md5, p, len); ngx_md5_update(&md5, conf->secret.data, conf->secret.len); ngx_md5_final(hash, &md5); for (i = 0; i < 16; i++) { n = ngx_hextoi(&start[2 * i], 2); if (n == NGX_ERROR || n != hash[i]) { goto not_found; } } v->len = len; v->valid = 1; v->no_cacheable = 0; v->not_found = 0; v->data = p; return NGX_OK; not_found: v->not_found = 1; return NGX_OK; }
static ngx_int_t ngx_http_shmtest_get(ngx_http_request_t *r){ ngx_int_t rc = NGX_HTTP_OK; ngx_str_t key = ngx_null_string; ngx_str_t value = ngx_null_string; int32_t ikey = 0; uint8_t value_type = VT_BINARY; uint32_t exptime = 0; uint32_t user_flags = 0; if(ngx_http_arg(r, (u_char*)"key", 3, &key)!=NGX_OK){ NLOG_ERROR("get arg 'key' failed!"); return NGX_HTTP_BAD_REQUEST; } if(key.len > 2 && key.data[0] == '0' && key.data[1] == 'x'){ key.data += 2; key.len -= 2; ikey = ngx_hextoi(key.data, key.len); ngx_str_set_int32(&key, &ikey); NLOG_DEBUG("use int key ikey=%d", ikey); } shmtest_main_conf_t* smcf; smcf = ngx_http_get_module_main_conf(r, ngx_http_shmtest_module); if(smcf == NULL){ NLOG_ERROR("get module ngx_http_shmtest_module's main conf failed!"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_shm_zone_t* zone = smcf->shmap; u_char* rsp = ngx_pcalloc(r->connection->pool, 256); int rsp_len = 0; rc = ngx_shmap_get(zone, &key, &value, &value_type, &exptime, &user_flags); if(ikey != 0){ if(rc == 0){ rsp_len = ngx_sprintf(rsp, "get(%d)={value=%V,exptime=%d,user_flags=%d}!\n", ikey,&value,exptime,user_flags)-rsp; }else{ rsp_len = ngx_sprintf(rsp, "get(%d) failed!\n", ikey)-rsp; } }else{ if(rc == 0){ rsp_len = ngx_sprintf(rsp, "get(%V)={value=%V,exptime=%d,user_flags=%d}!\n", &key,&value,exptime,user_flags)-rsp; }else{ rsp_len = ngx_sprintf(rsp, "get(%V) failed!\n", &key)-rsp; } } ngx_chain_t* chain = ngx_http_shmtest_resp(r, (char*)rsp, rsp_len); if(chain != NULL){ r->headers_out.content_length_n = rsp_len; }else{ r->headers_out.content_length_n = 0; } rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { }else{ rc = ngx_http_output_filter(r, chain); } return rc; }
static ngx_int_t ngx_http_shmtest_add_or_update(ngx_http_request_t *r,int func){ ngx_int_t rc = NGX_HTTP_OK; ngx_str_t key = ngx_null_string; int32_t ikey = 0; ngx_str_t value = ngx_null_string; char* szFunc = funcs[func]; if(ngx_http_arg(r, (u_char*)"key", 3, &key)!=NGX_OK){ NLOG_ERROR("get arg 'key' failed!"); return NGX_HTTP_BAD_REQUEST; } if(ngx_http_arg(r, (u_char*)"value", 5, &value)!=NGX_OK){ NLOG_ERROR("get arg 'value' failed!"); return NGX_HTTP_BAD_REQUEST; } //如果key开始为0x 表示使用数字的KEY. if(key.len > 2 && key.data[0] == '0' && key.data[1] == 'x'){ key.data += 2; key.len -= 2; ikey = ngx_hextoi(key.data, key.len); ngx_str_set_int32(&key, &ikey); NLOG_DEBUG("use int key ikey=%d", ikey); } uint64_t exptime = 0; ngx_str_t sexptime = ngx_null_string; if(ngx_http_arg(r, (u_char*)"exptime", 7, &sexptime)==NGX_OK){ exptime = ngx_parse_time(&sexptime, 1); } if(ikey != 0){ NLOG_DEBUG("%s(key=%d,value=%V,exptime=%d)", szFunc,ikey,&value,exptime); }else{ NLOG_DEBUG("%s(key=%V,value=%V,exptime=%d)", szFunc,&key,&value,exptime); } shmtest_main_conf_t* smcf; smcf = ngx_http_get_module_main_conf(r, ngx_http_shmtest_module); if(smcf == NULL){ NLOG_ERROR("get module ngx_http_shmtest_module's main conf failed!"); return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_shm_zone_t* zone = smcf->shmap; int ret = 0; switch(func){ case FUNC_ADD: ret = ngx_shmap_add(zone, &key,&value,VT_STRING,exptime,0); break; case FUNC_SET: ret = ngx_shmap_set(zone, &key,&value,VT_STRING,exptime,0); break; case FUNC_REPLACE: ret = ngx_shmap_replace(zone, &key,&value,VT_STRING,exptime,0); break; default: NLOG_ERROR("un process type [%d]", func); return NGX_HTTP_BAD_REQUEST; } char* rsp = ngx_pcalloc(r->connection->pool, 256); int rsp_len = 0; if(ret == 0){ rsp_len = sprintf(rsp, "%s success!\n", szFunc); }else{ rsp_len = sprintf(rsp, "%s failed!\n", szFunc); } ngx_chain_t* chain = ngx_http_shmtest_resp(r, rsp, rsp_len); if(chain != NULL){ r->headers_out.content_length_n = rsp_len; }else{ r->headers_out.content_length_n = 0; } rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { }else{ rc = ngx_http_output_filter(r, chain); } return rc; }
static ngx_int_t ngx_http_secure_link_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { u_char *p, *start, *end, *last; size_t len; ngx_int_t n; ngx_uint_t i; ngx_md5_t md5; ngx_http_secure_link_conf_t *conf; u_char hash[16]; conf = ngx_http_get_module_loc_conf(r, ngx_http_secure_link_module); if (conf->secret.len == 0) { goto not_found; } p = &r->unparsed_uri.data[1]; last = r->unparsed_uri.data + r->unparsed_uri.len; while (p < last) { if (*p++ == '/') { start = p; goto md5_start; } } goto not_found; md5_start: while (p < last) { if (*p++ == '/') { end = p - 1; goto url_start; } } goto not_found; url_start: len = last - p; if (end - start != 32 || len == 0) { goto not_found; } ngx_md5_init(&md5); ngx_md5_update(&md5, p, len); ngx_md5_update(&md5, conf->secret.data, conf->secret.len); ngx_md5_final(hash, &md5); for (i = 0; i < 16; i++) { n = ngx_hextoi(&start[2 * i], 2); if (n == NGX_ERROR || n != hash[i]) { goto not_found; } } v->len = len; v->valid = 1; v->no_cacheable = 0; v->not_found = 0; v->data = p; return NGX_OK; not_found: v->not_found = 1; return NGX_OK; }
static ngx_int_t ngx_http_auth_digest_verify_hash(ngx_http_request_t *r, ngx_http_auth_digest_cred_t *fields, u_char *hashed_pw) { u_char *p; ngx_str_t http_method; ngx_str_t HA1, HA2, ha2_key; ngx_str_t digest, digest_key; ngx_md5_t md5; u_char hash[16]; // the hashing scheme: // digest: MD5(MD5(username:realm:password):nonce:nc:cnonce:qop:MD5(method:uri)) // ^- HA1 ^- HA2 // verify: fields->response == MD5($hashed_pw:nonce:nc:cnonce:qop:MD5(method:uri)) // ha1 was precalculated and saved to the passwd file: md5(username:realm:password) HA1.len = 33; HA1.data = ngx_pcalloc(r->pool, HA1.len); p = ngx_cpymem(HA1.data, hashed_pw, 32); // calculate ha2: md5(method:uri) http_method.len = r->method_name.len+1; http_method.data = ngx_pcalloc(r->pool, http_method.len); if (http_method.data==NULL) return NGX_HTTP_INTERNAL_SERVER_ERROR; p = ngx_cpymem(http_method.data, r->method_name.data, r->method_end - r->method_name.data+1); ha2_key.len = http_method.len + r->uri.len + 1; ha2_key.data = ngx_pcalloc(r->pool, ha2_key.len); if (ha2_key.data==NULL) return NGX_HTTP_INTERNAL_SERVER_ERROR; p = ngx_cpymem(ha2_key.data, http_method.data, http_method.len-1); *p++ = ':'; p = ngx_cpymem(p, r->uri.data, r->uri.len); HA2.len = 33; HA2.data = ngx_pcalloc(r->pool, HA2.len); ngx_md5_init(&md5); ngx_md5_update(&md5, ha2_key.data, ha2_key.len-1); ngx_md5_final(hash, &md5); ngx_hex_dump(HA2.data, hash, 16); // calculate digest: md5(ha1:nonce:nc:cnonce:qop:ha2) digest_key.len = HA1.len-1 + fields->nonce.len-1 + fields->nc.len-1 + fields->cnonce.len-1 + fields->qop.len-1 + HA2.len-1 + 5 + 1; digest_key.data = ngx_pcalloc(r->pool, digest_key.len); if (digest_key.data==NULL) return NGX_HTTP_INTERNAL_SERVER_ERROR; p = ngx_cpymem(digest_key.data, HA1.data, HA1.len-1); *p++ = ':'; p = ngx_cpymem(p, fields->nonce.data, fields->nonce.len-1); *p++ = ':'; p = ngx_cpymem(p, fields->nc.data, fields->nc.len-1); *p++ = ':'; p = ngx_cpymem(p, fields->cnonce.data, fields->cnonce.len-1); *p++ = ':'; p = ngx_cpymem(p, fields->qop.data, fields->qop.len-1); *p++ = ':'; p = ngx_cpymem(p, HA2.data, HA2.len-1); digest.len = 33; digest.data = ngx_pcalloc(r->pool, 33); if (digest.data==NULL) return NGX_HTTP_INTERNAL_SERVER_ERROR; ngx_md5_init(&md5); ngx_md5_update(&md5, digest_key.data, digest_key.len-1); ngx_md5_final(hash, &md5); ngx_hex_dump(digest.data, hash, 16); // compare the hash of the full digest string to the response field of the auth header // and bail out if they don't match if (ngx_strcmp(digest.data, fields->response.data) != 0) return NGX_DECLINED; ngx_http_auth_digest_nonce_t nonce; ngx_uint_t key; ngx_http_auth_digest_node_t *found; ngx_slab_pool_t *shpool; ngx_http_auth_digest_loc_conf_t *alcf; ngx_table_elt_t *info_header; ngx_str_t hkey, hval; shpool = (ngx_slab_pool_t *)ngx_http_auth_digest_shm_zone->shm.addr; alcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_digest_module); nonce.rnd = ngx_hextoi(fields->nonce.data, 8); nonce.t = ngx_hextoi(&fields->nonce.data[8], 8); key = ngx_crc32_short((u_char *) &nonce.rnd, sizeof nonce.rnd) ^ ngx_crc32_short((u_char *) &nonce.t, sizeof(nonce.t)); int nc = ngx_atoi(fields->nc.data, fields->nc.len-1); if (nc<0 || nc>=alcf->replays){ fields->stale = 1; return NGX_DECLINED; } // make sure nonce and nc are both valid ngx_shmtx_lock(&shpool->mutex); found = (ngx_http_auth_digest_node_t *)ngx_http_auth_digest_rbtree_find(key, ngx_http_auth_digest_rbtree->root, ngx_http_auth_digest_rbtree->sentinel); if (found!=NULL && ngx_bitvector_test(found->nc, nc)){ if (ngx_bitvector_test(found->nc, 0)){ // if this is the first use of this nonce, switch the expiration time from the timeout // param to now+expires. using the 0th element of the nc vector to flag this... ngx_bitvector_set(found->nc, 0); found->expires = ngx_time() + alcf->expires; } // mark this nc as ‘used’ to prevent replays ngx_bitvector_set(found->nc, nc); // todo: if the bitvector is now ‘full’, could preemptively expire the node from the rbtree // ngx_rbtree_delete(ngx_http_auth_digest_rbtree, found); // ngx_slab_free_locked(shpool, found); ngx_shmtx_unlock(&shpool->mutex); // recalculate the digest with a modified HA2 value (for rspauth) and emit the // Authentication-Info header ngx_memset(ha2_key.data, 0, ha2_key.len); p = ngx_sprintf(ha2_key.data, ":%s", r->uri.data); ngx_memset(HA2.data, 0, HA2.len); ngx_md5_init(&md5); ngx_md5_update(&md5, ha2_key.data, r->uri.len); ngx_md5_final(hash, &md5); ngx_hex_dump(HA2.data, hash, 16); ngx_memset(digest_key.data, 0, digest_key.len); p = ngx_cpymem(digest_key.data, HA1.data, HA1.len-1); *p++ = ':'; p = ngx_cpymem(p, fields->nonce.data, fields->nonce.len-1); *p++ = ':'; p = ngx_cpymem(p, fields->nc.data, fields->nc.len-1); *p++ = ':'; p = ngx_cpymem(p, fields->cnonce.data, fields->cnonce.len-1); *p++ = ':'; p = ngx_cpymem(p, fields->qop.data, fields->qop.len-1); *p++ = ':'; p = ngx_cpymem(p, HA2.data, HA2.len-1); ngx_md5_init(&md5); ngx_md5_update(&md5, digest_key.data, digest_key.len-1); ngx_md5_final(hash, &md5); ngx_hex_dump(digest.data, hash, 16); ngx_str_set(&hkey, "Authentication-Info"); hval.len = sizeof("qop=\"auth\", rspauth=\"\", cnonce=\"\", nc=") + fields->cnonce.len + fields->nc.len + digest.len; hval.data = ngx_pcalloc(r->pool, hval.len); if (hval.data==NULL) return NGX_HTTP_INTERNAL_SERVER_ERROR; p = ngx_sprintf(hval.data, "qop=\"auth\", rspauth=\"%s\", cnonce=\"%s\", nc=%s", digest.data, fields->cnonce.data, fields->nc.data); info_header = ngx_list_push(&r->headers_out.headers); if (info_header == NULL) return NGX_HTTP_INTERNAL_SERVER_ERROR; info_header->key = hkey; info_header->value = hval; info_header->hash = 1; return NGX_OK; }else{ // nonce is invalid/expired or client reused an nc value. suspicious... ngx_shmtx_unlock(&shpool->mutex); return NGX_DECLINED; } }