Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Yoshinori Teraoka committed Oct 28, 2018
1 parent 0febedc commit 71da5a3
Show file tree
Hide file tree
Showing 6 changed files with 781 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

check_ajp
61 changes: 61 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# check_ajp

Nagios plugin for checking AJP13 Server

## Usage

```
Usage:
check_ajp [OPTIONS]
Application Options:
-A, --useragent= User-Agent header (default: check_http_go)
-a, --attr= Attributes (auth, jvmRoute,...)
-c, --crit= Critical time in second (default: 10.0)
-e, --expect= Expected status codes (csv)
-H, --vhost= Host header value
-I, --ipaddr= IP address or Server hostname (default: 127.0.0.1)
-k, --header= Additional headers
-m, --method= HTTP method (default: GET)
-P, --protocol= HTTP protocol (default: HTTP/1.0)
-p, --port= TCP Port (default: 8009)
-s, --ssl isSSL flag
-t, --timeout= Connect timeout in second (default: 1.0)
-u, --uri= URI (default: /)
-v, --verbose verbose output
-w, --warn= Warning time in second (default: 5.0)
-V, --version Show version
--json-key= JSON key
--json-value= Expected json value
--remote-addr= RemoteAddr header value
--remote-host= RemoteHost header value
Help Options:
-h, --help Show this help message
```

### example

```
./check_ajp -I server -u /checkHealth
AJP OK: 200 - 3 bytes in 0.013 second response time |time=0.012675s;;;0.000000 size=3B;;;0
```

```
$ ./check_ajp -I server -u /healthcheck --json-key status --json-value "ok"
AJP OK: 200 - 137 bytes in 0.012 second response time |time=0.012235s;;;0.000000 size=137B;;;0
{
"status": "ok"
}
```

## Limitations

Current version supported `GET` and `HEAD` method only.

## How to build

```
go build -o check_ajp
```
216 changes: 216 additions & 0 deletions ajp_request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
package main

import (
"bytes"
"errors"
"fmt"
"github.com/lunixbochs/struc"
"io"
"strings"
)

var SC_REQ_HEADER = map[string][]byte{
"accept": {0xA0, 0x01},
"accept-charset": {0xA0, 0x02},
"accept-encoding": {0xA0, 0x03},
"accept-language": {0xA0, 0x04},
"authorization": {0xA0, 0x05},
"connection": {0xA0, 0x06},
"content-type": {0xA0, 0x07},
"content-length": {0xA0, 0x08},
"cookie": {0xA0, 0x09},
"cookie2": {0xA0, 0x0A},
"host": {0xA0, 0x0B},
"pragma": {0xA0, 0x0C},
"referer": {0xA0, 0x0D},
"user-agent": {0xA0, 0x0E},
}

var SC_REQ_ATTR = map[string][]byte{
"context": {0x01}, // Not currently implemented
"servlet_path": {0x02}, // Not currently implemented
"remote_user": {0x03},
"auth_type": {0x04}, // Basic, Digest
"query_string": {0x05},
"route": {0x06},
"ssl_cert": {0x07},
"ssl_cipher": {0x08},
"ssl_session": {0x09},
"req_attribute": {0x0A}, // Name (the name of the attribut follows)
"ssl_key_size": {0x0B},
"secret": {0x0C},
"stored_method": {0x0D},
}

var METHOD = map[string]int{
"GET": 2,
"HEAD": 3,
/*
Other methods are not supported yet.
"OPTIONS": 1,
"POST": 4,
"PUT": 5,
"DELETE": 6,
"TRACE": 7,
"PROPFIND": 8,
"PROPPATCH": 9,
"MKCOL": 10,
"COPY": 11,
"MOVE": 12,
"LOCK": 13,
"UNLOCK": 14,
"ACL": 15,
"REPORT": 16,
"VERSION-CONTROL": 17,
"CHECKIN": 18,
"CHECKOUT": 19,
"UNCHECKOUT": 20,
"SEARCH": 21,
"MKWORKSPACE": 22,
"UPDATE": 23,
"LABEL": 24,
"MERGE": 25,
"BASELINE_CONTROL": 26,
"MKACTIVITY": 27,
*/
}

const JK_AJP13_FORWARD_REQUEST = 0x02

type RequestHeader struct {
Name string
Value string
}

type Attribute struct {
Code []byte
Value string
}

type AJP13ForwardRequest struct {
PrefixCode int
Method string
Uri string
Protocol string
RemoteAddr string
RemoteHost string
ServerName string
ServerPort int
IsSsl bool
Headers []*RequestHeader
Attributes []*Attribute
}

type encodeBool struct {
Value bool `struc:"bool"`
}

type encodeInt8 struct {
Value int `struc:"uint8"`
}

type encodeInt16 struct {
Value int `struc:"int16"`
}

type encodeString struct {
Size int `struc:"uint16,sizeof=Value"`
Value string `struc:[]byte`
Terminate []byte `struc:"[1]pad"`
}

func newAJP13ForwardRequest(o Options) AJP13ForwardRequest {
r := AJP13ForwardRequest{}
r.PrefixCode = JK_AJP13_FORWARD_REQUEST
r.Method = strings.ToUpper(o.Method)
r.Protocol = o.Protocol
r.IsSsl = o.Ssl
r.Uri = o.Uri
r.ServerName = o.Ipaddr
r.ServerPort = o.Port
if o.RemoteAddr != "" {
r.RemoteAddr = o.RemoteAddr
}
if o.RemoteHost != "" {
r.RemoteHost = o.RemoteHost
}
return r
}

func (r *AJP13ForwardRequest) appendHeader(header string) {
hdr := strings.SplitN(header, ": ", 2)
r.Headers = append(r.Headers, &RequestHeader{Name: strings.ToLower(hdr[0]), Value: hdr[1]})
}

func appendUint16(buf *bytes.Buffer, i int) {
struc.Pack(buf, &encodeInt16{Value: i})
}

func appendByte(buf *bytes.Buffer, i int) {
struc.Pack(buf, &encodeInt8{Value: i})
}

func appendString(buf *bytes.Buffer, s string) {
struc.Pack(buf, &encodeString{Value: s})
}

func appendBool(buf *bytes.Buffer, b bool) {
struc.Pack(buf, &encodeBool{Value: b})
}

func (r *AJP13ForwardRequest) validate() error {
var err error

if METHOD[r.Method] == 0 {
err = errors.New(fmt.Sprintf("%s method is not yet supported.", r.Method))
}

return err
}

func (r *AJP13ForwardRequest) sendRequest(w io.Writer) error {
var err error

var buf bytes.Buffer
appendByte(&buf, r.PrefixCode)
appendByte(&buf, METHOD[r.Method])
appendString(&buf, r.Protocol)
appendString(&buf, r.Uri)
appendString(&buf, r.RemoteAddr)
appendString(&buf, r.RemoteHost)
appendString(&buf, r.ServerName)
appendUint16(&buf, r.ServerPort)
appendBool(&buf, r.IsSsl)

// Headers
appendUint16(&buf, len(r.Headers))

for _, hdr := range r.Headers {
if SC_REQ_HEADER[strings.ToLower(hdr.Name)] != nil {
buf.Write(SC_REQ_HEADER[strings.ToLower(hdr.Name)])
} else {
appendString(&buf, strings.ToLower(hdr.Name))
}
appendString(&buf, hdr.Value)
}

// Attributes
for _, attr := range r.Attributes {
buf.Write(attr.Code)
appendString(&buf, attr.Value)
}

buf.Write([]byte{0xff})

// Packet Format (Server->Container)
// Byte 0 1 2 3 4...(n+3)
// Contents 0x12 0x34 Data Length (n) Data
_, err = w.Write([]byte{0x12, 0x34})
if err = struc.Pack(w, &encodeInt16{Value: buf.Len()}); err != nil {
return err
}
_, err = w.Write(buf.Bytes())

return err
}
Loading

0 comments on commit 71da5a3

Please sign in to comment.