Forum Discussion

Lee_Sutcliffe_5's avatar
Lee_Sutcliffe_5
Icon for Nimbostratus rankNimbostratus
Feb 15, 2013

Health monitors - XML API

Hi,

I'm trying to write a health monitor that sends an XML string, in order to receive some specific information. I've successfuly been able to replicate the query using cURL by replicating catured live, working traffic. However when I attempt to duplicate this into a health monitor I get a HTTP 400 Bad Request message:

This curl statement works and results in the output that follows, what is curious is that the first attempt fails with an authentication error but curl seems to try again and works. (some sensitive information has been removed)

curl -N -v \

-H 'Connection: Keep-Alive' \

-H 'Content-Type: text/xml; charset=utf-8' \

-H 'SOAPAction: "urn:domain-name.co.uk/service/check/Test"' \

--ntlm \

-u 'username:password' \

-d '' \

http://172.21.42.40:9003/service/check/11?wsdl

POST /Service/check/11?wsdl HTTP/1.1

Authorization: NTLM AAAAAAAAAAAAAAAAAAAAAAAAAAA=

User-Agent: curl/7.15.5 (i686-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5

Host: 172.21.42.40:9003

Accept: */*

Connection: Keep-Alive

Content-Type: text/xml; charset=utf-8

SOAPAction: "urn:domain-name.co.uk/service/check/Test"

Content-Length: 0

HTTP/1.1 401 Unauthorized

Content-Length: 0

Server: Microsoft-HTTPAPI/2.0

WWW-Authenticate: NTLM EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Date: Thu, 14 Feb 2013 16:06:16 GMT

POST /service/check/11?wsdl HTTP/1.1

Authorization: NTLM AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==

User-Agent: curl/7.15.5 (i686-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5

Host: 172.21.42.40:9003

Accept: */*

Connection: Keep-Alive

Content-Type: text/xml; charset=utf-8

SOAPAction: "urn:domain-name.co.uk/service/check/Test"

Content-Length: 154

HTTP/1.1 200 OK

Content-Length: 428

Content-Type: text/xml; charset=utf-8

Server: Microsoft-HTTPAPI/2.0

Date: Thu, 14 Feb 2013 16:06:16 GMT

9ecb118c-486c-4581-afda-0b59d367ed7e2013-02-14T16:06:10.42

The following is the equivilent health monitor of the above curl statement, originally this errored as the header value Content-Length was missing. I added this manually with values of both 0 and 154 but each time monitor errors. From looking at a capture of the monitor the POST request appears to be identical to the working curl one

Monitor (actual carriage return entered for clarity)

monitor TEST_MON {

defaults from http

recv ""

send POST /service/check/11?wsdl HTTP/1.1\r\n

Authorization: NTLM AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\r\n

Host: 172.21.42.40:9003\r\nAccept: */*\r\n

Connection: Keep-Alive\r\n

Content-Type: text/xml; charset=utf-8\r\n

SOAPAction: \"urn:domain-name.co.uk/service/check/Test\"\r\n

Content-Length: 154\r\n\r\n

}

results in the following

POST /service/check/11?wsdl HTTP/1.1

Authorization: NTLM AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==

Host: 172.21.42.40:9003

Accept: */*

Connection: Keep-Alive

Content-Type: text/xml; charset=utf-8

SOAPAction: "urn:domain-name.co.uk/service/check/Test"

Content-Length: 154

HTTP/1.1 400 Bad Request

Content-Length: 0

Server: Microsoft-HTTPAPI/2.0

Date: Thu, 14 Feb 2013 16:53:01 GMT

Changing the content-length to 0 produces the following output


HTTP/1.1 400 Bad Request

Content-Type: text/html; charset=us-ascii

Server: Microsoft-HTTPAPI/2.0

Date: Fri, 15 Feb 2013 09:49:09 GMT

Connection: close

Content-Length: 326

Bad Request

Bad Request - Invalid Verb

HTTP Error 400. The request verb is invalid.

  • what version are you running? i understand health monitor supports ntlm starting from 11.1.0.

     

     

    NTLM/NTLMv2 Authentication Support for HTTP/HTTPS Monitors

     

    http://support.f5.com/kb/en-us/products/big-ip_ltm/releasenotes/product/relnote-ltm-11-1-0.html
  • We run 10.2.x

     

    Not all the environments have been upgraded to 11 yet. When I put in a username and password in the monitor I got an authentication error and noted it was using basic auth. I removed this and manually entered the hash in the header and the authentication issue didn't occour.

     

  • I'd suggest you remove the Content-Length from the monitor as it won't be what is specified, especially as you are not using the user agent string in your monitor.
  • I only added the content length after receiving the the error.

     

    HTTP Error 411. The request must be chunked or have a content length.

     

  • I wonder then if you can find the correct length, or add in the User Agent string that curl used?
  • Thanks for the tip, I've tried with the same user-agent sting and still got a content length error.

     

    Trying the observed content length from a working curl simply returns a 400 error.

     

    So I suppose I'll need to try find out the actual content length of the monitor request
  • thanks, I've been using tcpdump to capture the monitor traffic and writing and output file to view this in wireshark.

     

    From what I understand the content-length is the length in bytes of the data, following the two carriage returns \r\n\r\n after the header.

     

    This being the case the data contains 154 characters including spaces, each chracter being represented by a 1 byte octet, thus surly the content length should be 154?

     

  • You could possibly alleviate some of your troubles by using an external monitor and cURL, which you know works.

     

     

    Create a copy of /config/monitors/sample_monitor and make the following changes:

     

     

    
    pidfile="/var/run/$MONITOR_NAME.$1..$2.pid"
    
    if [ -f $pidfile ]
    then
       kill -9 -`cat $pidfile` > /dev/null 2>&1
    fi
    
    echo "$$" > $pidfile
    
    node_ip=`echo $1 | sed 's/::ffff://'`
    
    RESULT=`curl -N -H 'Connection: Keep-Alive' -H 'Content-Type: text/xml; charset=utf-8' --ntlm -u 'username:password' -o /dev/null -s -w %{http_code} http://$node_ip:$2`
    
    if [ $RESULT -eq 200 ]
    then
         echo "up"
    fi
    
    rm -f $pidfile
    

     

     

    The external monitor consumes the IP address of the server to test in the first parameter ($1) and the port in the second ($2). The beauty of this approach is that you can go absolutely nuts with cURL. In my example I did a simple GET request and returned the HTTP status code using --write-out %{http_code}, but you could just as easily return the entire payload and check for a given value.

     

  • I'd thought about an external monitor, it was going to be my last resort.

     

    I should have done it earlier, it would have saved me hours! Thanks for your help, it's working a treat now :)

     

     

    Lee