Neowiz 는 시스템 설치를 PXE 와 kickstart 의 post script 를 이용하여 자동 관리를 하고 있습니다. 회사에서는 이 시스템을 P.I.P.E (본 뜻은 까먹었음. 그냥 파이프라고 함) 라고 칭합니다.
이번에 pipe system 을 migration 을 하고 있는데, 다음주 즈음 대략 몇백대를 동시에 설치할 일이 있어서, web daemon 을 apache 에서 lighttpd 로 변경을 했습니다.
centos 를 테스트 할 때까지만 해도 좋았는데.. redhat 9 의 anaconda 에서 lighttpd 기반에서 kickstart 파일을 받아오지 않는 난감한 사태가 발생을 하더군요. apache 로 가도 상관이 없지만, 몇백대씩 설치를 하려면 apache 로는 1대로는 버틸수가 없다는 문제가 발생을 합니다. 또한, pipe 의 특성상 설치를 하면서 시스템 내부에서 작업을 많이 하게 되는데, apache 로 몇백대를 설치할 경우에는 시스템이 과부하가 걸리게 됩니다.
그래서 고민하다가, 그래 한번 해결해 보자는 오기가 생기더군요. 원래 제가 이 바닥에서 뽀로꾸로 시작해서 오직
안되면 될 때까지 !!!
라는 신념으로 버텨온지라.. 이번에도 누가 이기나 한번 해 보자는 "자포자기"식으로 도전을 하게 되었습니다.
먼저.. 그럼 뭐가 문제일까.. 하고선 lighttpd 를 debug symbol 을 줘서 빌드한 후에 debugging 도 해 보았지만 뚜력한 이유를 알수가 없었고, 그럼 패킷이 어떻게 지나가나 보자.. 하고선 dump 를 떠 보았지만.. 시간만 속절없이 흘러가더군요. 그러다가.. 제대로 되는 패킷과 안되는 패킷을 비교하는 도중 아래의 붉은 글자 부분의 차이를 발견하게 됩니다.
* 400 Bad Request 경우
0x0000: 4510 0069 52fc 4000 4006 e980 7f00 0001 E..iR.@.@.......
0x0010: 7f00 0001 886f 0050 9443 d892 9435 6606 .....o.P.C...5f.
0x0020: 8018 0040 fe5d 0000 0101 080a 92a6 8da3 ...@.]..........
0x0030: 92a6 8a69 4745 5420 2f70 726f 6669 6c65 ...iGET./profile
0x0040: 2f64 6566 6175 6c74 2e72 6564 6861 742e /default.redhat.
0x0050: 392e 6933 3836 2f70 6970 652e 6b73 2048 9.i386/pipe.ks.H
0x0060: 5454 502f 312e 3009 0a TTP/1.0..
* 200 정상적인 경우
0x0000: 4510 0069 52fc 4000 4006 e980 7f00 0001 E..iR.@.@.......
0x0010: 7f00 0001 886f 0050 9443 d892 9435 6606 .....o.P.C...5f.
0x0020: 8018 0040 fe5d 0000 0101 080a 92a6 8da3 ...@.]..........
0x0030: 92a6 8a69 4745 5420 2f70 726f 6669 6c65 ...iGET./profile
0x0040: 2f64 6566 6175 6c74 2e72 6564 6861 742e /default.redhat.
0x0050: 392e 6933 3836 2f70 6970 652e 6b73 2048 9.i386/pipe.ks.H
0x0060: 5454 502f 312e 300d 0a TTP/1.0..
해당 자리는 carrige return (\r) 이 들어가야 할 자리인데.. 대체 09 가 무야 하고 찍어보니.. tab (\t) 를 찍고 있는 것입니다. 이제껏.. query 를 던지면서 왜 똑같은데 안되지 하고 있었는데.. RH9 anaconda 는
GET http://domain.com/uri\t\n
을 찍고 있었던 겁니다. 그러니 될 턱이 없지요 --; 이것 땜시 anaconda 소스와 lighttpd 의 소스를 까보면서 헛되이 시간을 보내고 있었던 것이었습니다. 알고나자 허탈함이 밀려 오면서.. (속으로는 이런 "씹x"...) 여기서 포기해야 하는가 하다가, 들인 시간이 아까와서 다시
안되면 될 때까지 !!!
의 정신으로, lighttpd 가 저 쿼리를 받아들일 수 있도록 수정해 보자는 말도 안되는 결심을 하게 됩니다. 그렇게 한참을 뒤져서 다음의 패치가 나오게 됩니다.
diff -urNp lighttpd-1.4.11.org/src/connections.c lighttpd-1.4.11/src/connections.c
--- lighttpd-1.4.11.org/src/connections.c 2006-07-21 00:27:44.000000000 +0900
+++ lighttpd-1.4.11/src/connections.c 2006-07-21 00:26:47.000000000 +0900
@@ -910,15 +910,21 @@ int connection_handle_read_state(server
/* check if we need the full package */
if (con->request.request->used == 0) {
buffer b;
+ char *_bptr;
b.ptr = c->mem->ptr + c->offset;
b.used = c->mem->used - c->offset;
+ /* fixed redhat 9 anaconda bug */
+ _bptr = strstr (b.ptr, "\t\n");
+ if ( _bptr != NULL ) *_bptr = '\r';
+
+ //log_error_write(srv, __FILE__, __LINE__, "ss", "request header1:", b.ptr);
if (NULL != (h_term = buffer_search_rnrn(&b))) {
/* \r\n\r\n found
* - copy everything incl. the terminator to request.request
*/
buffer_copy_string_len(con->request.request,
b.ptr,
h_term - b.ptr + 4);
간단하게, \t\n 을 찾아서 \t 를 \r 로 바꾸는 거죠. ^^; 이렇게 하다가 갑자기 포인터로 구현을 해 보고 싶더군요. 전 앞에서 밝혔다 시피 뽀로꾸와 수많은 닥질의 경험으로 오늘날의 바탕을 마련했는데, C 역시 그냥 마구잡이로 소스를 써내려간 막가파로서, 포인터에 대한 이해가 전혀 없이 사용해 왔는데 갑자기 포인터가 이해가 되는 듯한 느낌이 들었습니다. 그래서 별 소용은 없지만 다음과 같은 코드도 만들게 됩니다.
diff -urNp lighttpd-1.4.11.org/src/connections.c lighttpd-1.4.11/src/connections.c
--- lighttpd-1.4.11.org/src/connections.c 2006-07-21 00:27:44.000000000 +0900
+++ lighttpd-1.4.11/src/connections.c 2006-07-21 00:26:47.000000000 +0900
@@ -910,15 +910,31 @@ int connection_handle_read_state(server
/* check if we need the full package */
if (con->request.request->used == 0) {
buffer b;
+ char *_bptr;
b.ptr = c->mem->ptr + c->offset;
b.used = c->mem->used - c->offset;
+ /* fixed redhat 9 anaconda bug */
+ if ( strchr (b.ptr, '\t') != NULL ) {
+ _bptr = b.ptr;
+ while ( *_bptr != 0 ) {
+ if ( *_bptr == '\t' ) {
+ if ( *(_bptr+1) == '\n' ) {
+ *_bptr = '\r';
+ break;
+ }
+ } else *_bptr++;
+ }
+ }
+ /* fixed redhat 9 anaconda bug */
+
+ //log_error_write(srv, __FILE__, __LINE__, "ss", "request header1:", b.ptr);
if (NULL != (h_term = buffer_search_rnrn(&b))) {
/* \r\n\r\n found
* - copy everything incl. the terminator to request.request
*/
buffer_copy_string_len(con->request.request,
b.ptr,
h_term - b.ptr + 4);
누워서 침뱉기 일지는 모르겠지만.. 포인터를 사용하면서 한번에 이렇게 써 내려간 적은 처음인 듯 싶습니다. 예전에 기타를 칠때도 한동안 안 늘다가 어느날 갑자기 못치던 것을 치게 되는 경우가 있었는데, 마치 오늘 위의 코드가 그런 경우인 듯 싶습니다. 스스로가 감탄스럽더군요. (저는 가끔 제멋에 뻑 갈때가 종종 있습니다. ^^)
RH9 의 말도 안되는 request query 덕분에, 고생도 엄청 했고, 저런 것까지 처리를 해 주고 있는 apache 에 대해서 새삼스럽게 존경을 하게 되었으며 (괜히 apache 라고 하는게 아니구나..), 이런 코드를 한번만에 만들어 낸 자신에게 감탄도 하고.. (워낙 설계라는 것 없이 하나 보니, 한번에 쓰는 경우는 정말 드물었죠..), 금방 위치를 찾아낸 것도 감탄 스럽고.. 몸은 힘들었지만, 마음은 그대로 나름대로 뿌듯합니다.
처음에는 google 신에게 구걸을 하려고 시도를 했으나, 결국에는 찾지를 못하여.. 이 글로 내가 했던 고생을 좀 덜 수 있으면 다행이라 생각하고 후기를 남깁니다.
Comments List
관리자만 볼 수 있는 댓글입니다.
ㅎㅎ 버그가 맞네요. \t\n 을 \r\n 으로 하는 것이 목적인데, 제 코드는 \t\r 을 만들고 있었네요. ㅋㅋ 오류 알려 주셔서 감사합니다.
뭐 어차피 이 코드는 실제 패치에 사용한 코드가 아니라 그냥 심심해서 만들어본 코드였으니 상관은 없습니다만..
그리고 요즘 버전은 이 패치가 맞지 않습니다. 그래서 패치 자체도 바뀌었죠. 요즘은..
+ /* if rh9 support flag on, convert \t\n to \r\n */
+ if ( srv->config_storage[0]->rh9support ) {
+ //log_error_write (srv, __FILE__, __LINE__, "s", "RH9 Support flag on"
+ if ( ch == '\\t' && b.ptr[i+1] == '\n' )
+ b.ptr[i] = '\\r';
+ }
이정도로 처리가 되고 있네요 :-)
역쉬 뽀로꾸 마왕.. 그거땜시 내 점심이 날아간겨?
이야.. 그때 그놈이군요.. 당황케했던.. 결국 발견.. @.@