busybox_httpd, http, CGI

2013-01-14 17:33 850人阅读 评论(0) 收藏 举报


本文章已收录于:






busybox 的安装      busybox-1.18.5.tar.bz2
      make menuconfig     # This creates a file called ".config"
      make                # This creates the "busybox" executable
      make install        # or make CONFIG_PREFIX=/path/from/root install
 
You will probably need to make your busybox binary setuid root to ensure all configured applets will work properly.

      chmod 4755 ./_install/bin/busybox

 

 

 

***********************************************************************************/
                   httpd server   Haserl
                      http://haserl.sourceforge.net/manpage.html /***********************************************************************************/
使用选项
$ sudo ./busybox httpd -f   // -f 前景模式,可以看打印  // -f == 非daemon()
 httpd -p 8080 -h $HOME/public_html
 httpd -u www
 httpd -p 80 -u 80 -h $PWD -c /etc/httpd.conf -r "Web Server Authentication"
 *      foo=`httpd -d $foo`             # decode "Hello%20World" as "Hello World"
 *      bar=`httpd -e "<Hello World>"`  # encode as "&#60Hello&#32World&#62"
     
配置文件
 服务器根目录的设置 home_httpd  * H:/serverroot     # define the server root. It will override -h
 
 特殊IP的访问控制 deny > allow > deny *   拒绝后也是空白?HTTP 錯誤 403 - 禁止
   * A:172.20.         # Allow address from 172.20.0.0/16
   * D:*               # Deny from other IP connections
  特殊页面的设置     404不起作用?绝对路径
   * E404:/path/e404.html # /path/e404.html is the 404 (not found) error page
   * I:index.html      # Show index.html when a directory is requested
  代理地址转换 * P:/url:[http://]hostname[:port]/new/path
   # When /urlXXXXXX is requested, reverse proxy it to http://hostname[:port]/new/pathXXXXXX   目录权限控制     
   * /cgi-bin:foo:bar  # Require user foo, pwd bar on urls starting with /cgi-bin/
    server: Http头域中包含"WWW-Authenticate: Basic realm=\".\"\r\n"  // 客户端会弹出window链接到IP对话框要求输入用户名密码
    client: Authorization: Basic YWFhOmJiYg==\r\n  // 输入用户名和密码后,以加密形式送出
    httpd 中的权限表: 是按照URL长度从大到小排列的!所以查找时按照最近匹配原则。
  文件的执行程序
   * .au:audio/basic   # additional mime type for audio.au files
   * *.php:/path/php   # run xxx.php through an interpreter
     
HTTP协议:
 GET:
  在请求时将请求的内容添加到URL后, http://192.168.60.129/cgi-bin/xmlPost?Text_Field=ding&Radio_Button=2&Submit=Submit    把问号后的全部记录到环境变量 "QUERY_STRING"
 POST:  
  http://192.168.60.129/cgi-bin/xmlPost   在请求的头域中找内容长度"Content-length:" 记录到环境变量"CONTENT_LENGTH",根据长度从标准输入流中取得POST的内容
  fgets(xmlData, dataLen + 1, stdin);  // 最多只能读入n-1个字符。读入结束后,系统将自动在最后加'\0',并以str作为函数值返回
   xmlData[]: Text_Field=ding&Radio_Button=2&Text_Area=lidan&Submit=Submit  
   // <input type=submit value=POST> 没有name, 数据中就没有这一项  
 请求有图片的网页:会发送2次请求
  dld:handleIncoming enter(buf = GET /cgi-bin/getPageInfo?deviceInfo.html HTTP/1.1)...
  dld:handleIncoming enter(buf = GET /cgiPic/cisco_Logo.gif HTTP/1.1)...
 
httpd.c 代码流程

1. main(): 
          if (daemon(1, 0) < 0)   // nochdir = 0, 进入根目录; noclose = 0, 不输出任何打印!!!
           运行成功后,父进程自杀;后续都是子进程的打印以及处理!!!
  2. mini_httpd():


  父进程循环等待客户端的请求
  子1进程将0,1重定向到与客户端通信的socket
   并处理请求 handle_incoming_and_exit
 3. handle_incoming_and_exit  // 分析GET行,解析头域Auth..., 解析URL, 调用CGI或者File
  send_cgi_and_exit  // CGI的处理:  
    子2进程将0,1重定向到管道,        // dup2(outFd, 1);
   CGI程序从toCgi管道中读,写入fromCgi管道     // execv(realpath_buff, argp); 子进程执行CGI程序
    父2进程=子1: 0, 1为与客户通信的socket
   还有与子2进程通信的2个管道
 4. cgi_io_loop_and_exit(与子进程通信的2个管道)  // 父2进程处理
         读 从0(socket)来的数据, 父进程写到toCgi[1]中        // 子进程从toCgi[0]中读。通过以上子2进程0,1重定向实现!!!
         读 从fromCgi[0]中来的数据,父进程写到1(socket)中。  // CGI生成的数据子进程写到fromCgi[1]中。同上!!!
         1. 还有客户端的数据时,打开toCgi,准备写入
         2. 有需要接受post的数据时,从0读,父写到 toCgi
         3. 否则关闭toCgi
         4. 从 缓存hdr_ptr 写到 toCgi
         5. 从 0 读,保存到缓存
         6. 从 fromCgi 读,保存到rbuf,然后写到 1 // 可能加入头域等东东

 5. #if ENABLE_FEATURE_HTTPD_BASIC_AUTH
  a. 在分析请求的头域中,如果含有 "Authorization:" , 则提取用户名密码进行验证
   验证 check_user_passwd : 与配置文件httpd.conf 中的"/file:user:pass"字段 进行比较
  b. 验证失败,则发送401  // send_headers_and_exit(HTTP_UNAUTHORIZED)
   WWW-Authenticate: Basic realm="SEPC89C1DA3532B"\r\n  // server response head中含有此字段,客户端浏览器会弹出window窗口,要求输入密码
 6. ME:开启CUCM鉴权流程
 

ENABLE_FEATURE_HTTPD_BASIC_AUTH
    ENABLE_AUTH_TO_CUCM
     V:/CGI/Screenshot
  7. ME: httpd.conf
   U:/CGI/Screenshot:/cgi-bin/screenShot
   V:/CGI/Screenshot


    

httpd.c Q&&A
 0. 为什么handle_incoming_and_exit后的打印在控制台跟踪不到呢?     
         在 mini_httpd 函数中 //  即向0,1中读写的东西,实际都送到了套接字中了,因此后面的打印在控制台屏幕显示不出来,而在抓包工具中的包中!!!
    

n = accept(server_socket, &fromAddr.u.sa, &fromAddr.len);
   if (fork() == 0) {
    /* child */
    /* Do not reload config on HUP */
    signal(SIGHUP, SIG_IGN);
    close(server_socket);
    xmove_fd(n, 0);    // 把  0 标准输入重定向到 打开的套接字,并关闭 n
    xdup2(0, 1);       // 把  1标准输出重定向到 0.  
    handle_incoming_and_exit(&fromAddr);
   }


 0. ENABLE_FEATURE_HTTPD_BASIC_AUTH 默认是打开的,为什么访问网页时没有要求输入密码?
  客户端没有送密码 且 配置文件也没有配置 就默认为通过验证。
  如何打开输入密码框: 在httpd.conf中加入 /cgi-bin:aaa:bbb,第一次无密码验证失败后,要求输入密码  
 1. 错误505 不支持的版本 // http/1.1 not ,
 2. busybox 中的 getLine() !!!注意好多全局的变量!!!
  读头域到buf中,遇到/r/n变为\0, 没有处理完,继续处理,直到读的内容处理都处理完了,才再读 
 3. 配置文件无P:,为什么会走到ENABLE_FEATURE_HTTPD_PROXY 代理的处理中?
     为什么send_cgi_and_exit 中的putenv setenv 有问题,走不下去? // 都是入参相关的变量
   局部变量指针等在开头赋值,中间处理到CUCM鉴权,socket通信后,
   前面的指针的值莫名其秒的变了:指针不是空,printf后死掉,应该是超长 // strerror buflen=2147439428???
    原因: char head_for_cucm_auth[] = {0};  // 竟然没有大小,导致栈空间被踩了,!!!
     另外局部数组 不要定义太大了。 // char * 8192
 4. 为什么没有-c时,会有错误打印 ?// httpd: config error 'U:/CGI/Execute:/cgi-bin/Execute' in 'httpd.conf'
  没有匹配任何一个分支,走到最后就会打印错误
   没有 -c, 也没有etc中的,就取当前路径下的httpd.conf 并且修改为 TRY_CURDIR_PARSE ,就走不进 U P
 5. 为何配置P不起作用   // #if ENABLE_FEATURE_HTTPD_PROXY 默认打开的
  if (flag == FIRST_PARSE && ch == 'P') {  //busybox要求第一次/etc/httpd.config(or -c /tmp/test/httpd.conf)才解析配置文件的某些项,我改动时删除了 flag 限制!!!  
   busybox 中P的链表是从最后一条在表头,倒序,且比较时,按照url_from的长度匹配的方式。
    (如果配置了P:/:/cgi-bin/getPageInfo, 导致 / /aaa 可能都匹配同一个)      // 我改动为完全匹配
     只要配置"/", 代理重入时,就会再次匹配上,从而导致死循环,out of memory!
 6. 为什么get可以,Post时,cucm Auth失败,返回500?
  因为:收到的字段的顺序是不固定的,取得Authorization: Basic ZGxkOmRsZA==\r\n 后的密码要保存一份,以免被后续的覆盖。
 
 // gcc 编译的,在虚拟机上跑的httpd, IP: 用桥接的 http://10.50.146.14:8080/cgi-bin/test-get?Text_Field=&Submit=Submit  
 7. httpd:bind: 地址已经被使用
  80端口在虚拟机上被其他进程使用了,话机里应该没有使用它的。
   netstat -an |grep :80
   ./busybox httpd -p 8080
 8. 为什么执行test-get时,显示的空白  
  cat -A test-get // 查看 多了回车 ^M
   vi 中不可见的 :set ff=unix
   vi里面用一个命令(:%s/^m//g)删除即可。  
   
   
CGI
 1. 在httpd 运行的目录下建立目录 cgi-bin and cgiPic,
  cgi-bin中放入 可执行文件
  cgiPic 中放入 图片 或者 弹出页面 
  // 可执行文件读取某html文件,此文件中含有图片或者弹出页面, 其存放位置应该相对于 读取他们的可执行文件,而不是包含他们的html文件
  eg. <IMG SRC="../cgiPic/cisco_Logo.gif"      
 2. 网页中的链接使用相对路径
 3. 根目录: 默认的根目录是httpd 运行的目录
  配置文件:H:/...  > -h /usr/...
 4. http response head 如果不完整的话,wireShark是跟踪不到服务器回应的包的!!!
 6. 仅仅CGI程序的错误会导致“找不到伺服器或 DNS 錯誤”!!!
  可能CGI程序挂掉了,webServer停在那里,没有给客户端回应。
 7. 头域的区分:每行后面有 /r/n ;  结尾有 /r/n /r/n , 后面是 




  • 上一篇introduce
  • 下一篇线程



busybox 的安装      busybox-1.18.5.tar.bz2
      make menuconfig     # This creates a file called ".config"
      make                # This creates the "busybox" executable
      make install        # or make CONFIG_PREFIX=/path/from/root install
 
You will probably need to make your busybox binary setuid root to ensure all configured applets will work properly.

      chmod 4755 ./_install/bin/busybox

 

 

 

***********************************************************************************/
                   httpd server   Haserl
                      http://haserl.sourceforge.net/manpage.html /***********************************************************************************/
使用选项

$ sudo ./busybox httpd -f   // -f 前景模式,可以看打印  // -f == 非daemon()
  httpd -p 8080 -h $HOME/public_html
  httpd -u www
  httpd -p 80 -u 80 -h $PWD -c /etc/httpd.conf -r "Web Server Authentication"
  *      foo=`httpd -d $foo`             # decode "Hello%20World" as "Hello World"
  *      bar=`httpd -e "<Hello World>"`  # encode as "<Hello World>"


     
配置文件
 服务器根目录的设置 home_httpd  * H:/serverroot     # define the server root. It will override -h
 
 特殊IP的访问控制 deny > allow > deny *   拒绝后也是空白?HTTP 錯誤 403 - 禁止
   * A:172.20.         # Allow address from 172.20.0.0/16
   * D:*               # Deny from other IP connections
  特殊页面的设置     404不起作用?绝对路径
   * E404:/path/e404.html # /path/e404.html is the 404 (not found) error page
   * I:index.html      # Show index.html when a directory is requested
  代理地址转换 * P:/url:[http://]hostname[:port]/new/path
   # When /urlXXXXXX is requested, reverse proxy it to http://hostname[:port]/new/pathXXXXXX   目录权限控制     
   * /cgi-bin:foo:bar  # Require user foo, pwd bar on urls starting with /cgi-bin/
    server: Http头域中包含"WWW-Authenticate: Basic realm=\".\"\r\n"  // 客户端会弹出window链接到IP对话框要求输入用户名密码
    client: Authorization: Basic YWFhOmJiYg==\r\n  // 输入用户名和密码后,以加密形式送出
    httpd 中的权限表: 是按照URL长度从大到小排列的!所以查找时按照最近匹配原则。
  文件的执行程序
   * .au:audio/basic   # additional mime type for audio.au files
   * *.php:/path/php   # run xxx.php through an interpreter
     
HTTP协议:
 GET:
  在请求时将请求的内容添加到URL后, http://192.168.60.129/cgi-bin/xmlPost?Text_Field=ding&Radio_Button=2&Submit=Submit    把问号后的全部记录到环境变量 "QUERY_STRING"
 POST:  
  http://192.168.60.129/cgi-bin/xmlPost   在请求的头域中找内容长度"Content-length:" 记录到环境变量"CONTENT_LENGTH",根据长度从标准输入流中取得POST的内容
  fgets(xmlData, dataLen + 1, stdin);  // 最多只能读入n-1个字符。读入结束后,系统将自动在最后加'\0',并以str作为函数值返回
   xmlData[]: Text_Field=ding&Radio_Button=2&Text_Area=lidan&Submit=Submit  
   // <input type=submit value=POST> 没有name, 数据中就没有这一项  
 请求有图片的网页:会发送2次请求
  dld:handleIncoming enter(buf = GET /cgi-bin/getPageInfo?deviceInfo.html HTTP/1.1)...
  dld:handleIncoming enter(buf = GET /cgiPic/cisco_Logo.gif HTTP/1.1)...
 
httpd.c 代码流程
 1. main():
         if (daemon(1, 0) < 0)   // nochdir = 0, 进入根目录; noclose = 0, 不输出任何打印!!!
          运行成功后,父进程自杀;后续都是子进程的打印以及处理!!!
 2. mini_httpd():
  父进程循环等待客户端的请求
  子1进程将0,1重定向到与客户端通信的socket
   并处理请求 handle_incoming_and_exit
 3. handle_incoming_and_exit  // 分析GET行,解析头域Auth..., 解析URL, 调用CGI或者File
  send_cgi_and_exit  // CGI的处理:  
    子2进程将0,1重定向到管道,        // dup2(outFd, 1);
   CGI程序从toCgi管道中读,写入fromCgi管道     // execv(realpath_buff, argp); 子进程执行CGI程序
    父2进程=子1: 0, 1为与客户通信的socket
   还有与子2进程通信的2个管道
 4. cgi_io_loop_and_exit(与子进程通信的2个管道)  // 父2进程处理
         读 从0(socket)来的数据, 父进程写到toCgi[1]中        // 子进程从toCgi[0]中读。通过以上子2进程0,1重定向实现!!!
         读 从fromCgi[0]中来的数据,父进程写到1(socket)中。  // CGI生成的数据子进程写到fromCgi[1]中。同上!!!
         1. 还有客户端的数据时,打开toCgi,准备写入
         2. 有需要接受post的数据时,从0读,父写到 toCgi
         3. 否则关闭toCgi
         4. 从 缓存hdr_ptr 写到 toCgi
         5. 从 0 读,保存到缓存
         6. 从 fromCgi 读,保存到rbuf,然后写到 1 // 可能加入头域等东东

 5. #if ENABLE_FEATURE_HTTPD_BASIC_AUTH
  a. 在分析请求的头域中,如果含有 "Authorization:" , 则提取用户名密码进行验证
   验证 check_user_passwd : 与配置文件httpd.conf 中的"/file:user:pass"字段 进行比较
  b. 验证失败,则发送401  // send_headers_and_exit(HTTP_UNAUTHORIZED)
   WWW-Authenticate: Basic realm="SEPC89C1DA3532B"\r\n  // server response head中含有此字段,客户端浏览器会弹出window窗口,要求输入密码
 6. ME:开启CUCM鉴权流程
  ENABLE_FEATURE_HTTPD_BASIC_AUTH
   ENABLE_AUTH_TO_CUCM
    V:/CGI/Screenshot
 7. ME: httpd.conf
  U:/CGI/Screenshot:/cgi-bin/screenShot
  V:/CGI/Screenshot
    

httpd.c Q&&A
 0. 为什么handle_incoming_and_exit后的打印在控制台跟踪不到呢?     
         在 mini_httpd 函数中 //  即向0,1中读写的东西,实际都送到了套接字中了,因此后面的打印在控制台屏幕显示不出来,而在抓包工具中的包中!!!
 

n = accept(server_socket, &fromAddr.u.sa, &fromAddr.len);
   if (fork() == 0) {
    /* child */
    /* Do not reload config on HUP */
    signal(SIGHUP, SIG_IGN);
    close(server_socket);
    xmove_fd(n, 0);    // 把  0 标准输入重定向到 打开的套接字,并关闭 n
    xdup2(0, 1);       // 把  1标准输出重定向到 0.  
    handle_incoming_and_exit(&fromAddr);
   }


 0. ENABLE_FEATURE_HTTPD_BASIC_AUTH 默认是打开的,为什么访问网页时没有要求输入密码?
  客户端没有送密码 且 配置文件也没有配置 就默认为通过验证。
  如何打开输入密码框: 在httpd.conf中加入 /cgi-bin:aaa:bbb,第一次无密码验证失败后,要求输入密码  
 1. 错误505 不支持的版本 // http/1.1 not ,
 2. busybox 中的 getLine() !!!注意好多全局的变量!!!
  读头域到buf中,遇到/r/n变为\0, 没有处理完,继续处理,直到读的内容处理都处理完了,才再读 
 3. 配置文件无P:,为什么会走到ENABLE_FEATURE_HTTPD_PROXY 代理的处理中?
     为什么send_cgi_and_exit 中的putenv setenv 有问题,走不下去? // 都是入参相关的变量
   局部变量指针等在开头赋值,中间处理到CUCM鉴权,socket通信后,
   前面的指针的值莫名其秒的变了:指针不是空,printf后死掉,应该是超长 // strerror buflen=2147439428???
    原因: char head_for_cucm_auth[] = {0};  // 竟然没有大小,导致栈空间被踩了,!!!
     另外局部数组 不要定义太大了。 // char * 8192
 4. 为什么没有-c时,会有错误打印 ?// httpd: config error 'U:/CGI/Execute:/cgi-bin/Execute' in 'httpd.conf'
  没有匹配任何一个分支,走到最后就会打印错误
   没有 -c, 也没有etc中的,就取当前路径下的httpd.conf 并且修改为 TRY_CURDIR_PARSE ,就走不进 U P
 5. 为何配置P不起作用   // #if ENABLE_FEATURE_HTTPD_PROXY 默认打开的
  if (flag == FIRST_PARSE && ch == 'P') {  //busybox要求第一次/etc/httpd.config(or -c /tmp/test/httpd.conf)才解析配置文件的某些项,我改动时删除了 flag 限制!!!  
   busybox 中P的链表是从最后一条在表头,倒序,且比较时,按照url_from的长度匹配的方式。
    (如果配置了P:/:/cgi-bin/getPageInfo, 导致 / /aaa 可能都匹配同一个)      // 我改动为完全匹配
     只要配置"/", 代理重入时,就会再次匹配上,从而导致死循环,out of memory!
 6. 为什么get可以,Post时,cucm Auth失败,返回500?
  因为:收到的字段的顺序是不固定的,取得Authorization: Basic ZGxkOmRsZA==\r\n 后的密码要保存一份,以免被后续的覆盖。
 
 // gcc 编译的,在虚拟机上跑的httpd, IP: 用桥接的 http://10.50.146.14:8080/cgi-bin/test-get?Text_Field=&Submit=Submit  
 7. httpd:bind: 地址已经被使用
  80端口在虚拟机上被其他进程使用了,话机里应该没有使用它的。
   netstat -an |grep :80
   ./busybox httpd -p 8080
 8. 为什么执行test-get时,显示的空白  
  cat -A test-get // 查看 多了回车 ^M
   vi 中不可见的 :set ff=unix
   vi里面用一个命令(:%s/^m//g)删除即可。  
   
   
CGI
 1. 在httpd 运行的目录下建立目录 cgi-bin and cgiPic,
  cgi-bin中放入 可执行文件
  cgiPic 中放入 图片 或者 弹出页面 
  // 可执行文件读取某html文件,此文件中含有图片或者弹出页面, 其存放位置应该相对于 读取他们的可执行文件,而不是包含他们的html文件
  eg. <IMG SRC="../cgiPic/cisco_Logo.gif"      
 2. 网页中的链接使用相对路径
 3. 根目录: 默认的根目录是httpd 运行的目录
  配置文件:H:/...  > -h /usr/...
 4. http response head 如果不完整的话,wireShark是跟踪不到服务器回应的包的!!!
 6. 仅仅CGI程序的错误会导致“找不到伺服器或 DNS 錯誤”!!!
  可能CGI程序挂掉了,webServer停在那里,没有给客户端回应。
 7. 头域的区分:每行后面有 /r/n ;  结尾有 /r/n /r/n , 后面是