Decompiled ifxjdbc.jar (4.50.JC10, build 146, 2023-03-07) with CFR 0.152
into build/jdbc-src/. The decompiled tree is gitignored — it's a
clean-room understanding reference, not shipped code.
Findings landed in two artifacts:
JDBC_NOTES.md — the reverse-lookup index:
- JAR identity (SHA256, manifest, line counts)
- Package layout (com.informix.{asf,jdbc,lang} are the load-bearing
packages; org.bson and the JDBC API surface get ignored)
- Class index mapping each wire-protocol concern to the responsible
Java class. Highlights:
- com.informix.asf.Connection (the wire transport / login PDU)
- com.informix.asf.IfxData{Input,Output}Stream (framing primitives)
- com.informix.jdbc.IfxMessageTypes (140+ message-tag constants)
- com.informix.lang.JavaToIfxType / IfxToJavaType (codecs)
- com.informix.jdbc.IfxSqli / IfxSqliConnect (the SQLI state machine)
- Auth landscape: plain-password is inline in the binary login PDU;
PAM is a server-initiated post-login challenge/response; CSM is
removed from this driver (literally throws an error if you try)
PROTOCOL_NOTES.md — the byte-level wire-format reference:
- Endianness: big-endian, network byte order (confirmed from
JavaToIfxInt source)
- Width table: SmallInt 2B, Int 4B, BigInt 8B, plus the legacy 10-byte
LongInt that we skip for MVP
- 16-bit alignment requirement for variable-length payloads — every
string/decimal/datetime is 0-padded if odd-length, missing this
desynchronizes the parser
- Login PDU structure decoded byte-by-byte from encodeAscBinary():
SLheader (6 bytes) + PFheader with markers 100/101/104/106/107/
108/116/127, capability bitfield, env vars, process info, app name
- Disconnection: bare [short SQ_EXIT=56] both directions, no header
- Post-login messages have NO header — protocol is stream-oriented:
[short tag][payload][short tag][payload]...
- Message-type tag table categorized by purpose
- Open questions list and cross-check matrix tracking what's
JDBC-derived vs PCAP-confirmed
DECISION_LOG.md additions:
- ifxjdbc.jar 4.50.JC10 selected as JDBC reference; CFR 0.152 as decompiler
- CSM is officially dead — never plan for it
- Plain-password auth is single-round-trip (no challenge/response)
- Wire-framing primitives locked in for _protocol.py
- Container credentials: user=informix, password=in4mix, on port 9088,
TLS off
Phase 0 exit gate: criteria #1 (login layout), #2 (message-type tags),
#3 (SELECT 1 hypothesis) are derived from JDBC. PCAP capture (task #7)
and cross-reference (task #2) remaining to corroborate.
170 lines
13 KiB
Markdown
170 lines
13 KiB
Markdown
# IBM JDBC Driver — Wire Protocol Class Index
|
|
|
|
> **Phase 0 spike artifact.** Reverse-lookup index into the decompiled IBM Informix JDBC driver. This document tells us which Java class to read when we want to understand how the JDBC driver implements a given wire-protocol concern.
|
|
>
|
|
> **Legal note**: the decompiled source lives in `build/jdbc-src/` and is **not committed to this repository**. It is consulted as a clean-room understanding reference only. The Python implementation in `src/informix_db/` is written from `PROTOCOL_NOTES.md` (which cites both the observed packet bytes and the JDBC class+method that emits them), never copied from the Java source.
|
|
|
|
---
|
|
|
|
## JAR identity
|
|
|
|
| Field | Value |
|
|
|-------|-------|
|
|
| Source | `/home/rpm/bingham/rtmt/lib/ifxjdbc.jar` (user-provided; an IBM tooling/RTMT install) |
|
|
| Working copy | `build/ifxjdbc.jar` |
|
|
| SHA256 | `dc5622cb4e95678d15836b684b6ef1783d37bc0cdd2725208577fc300df4e5f1` |
|
|
| `Implementation-Title` | `Informix JDBC Driver` |
|
|
| `Implementation-Version` | `4.50.10-SNAPSHOT` |
|
|
| `Build-Date` | `2023-03-07T11:30:44-0600` |
|
|
| `Build-Number` | `146` |
|
|
| `Main-Class` | `com.informix.jdbc.Version` (printable: "IBM Informix JDBC Driver Version 4.50.JC10") |
|
|
| Total entries | 685 (.class files) |
|
|
| Decompiled .java files | 478 |
|
|
|
|
## Decompilation
|
|
|
|
```bash
|
|
java -jar build/tools/cfr.jar build/ifxjdbc.jar --outputdir build/jdbc-src/ --silent
|
|
```
|
|
|
|
CFR version: 0.152 (May 2024). Downloaded from https://github.com/leibnitz27/cfr/releases/download/0.152/cfr-0.152.jar.
|
|
|
|
---
|
|
|
|
## Top-level package layout
|
|
|
|
```
|
|
com.informix.asf # wire-transport layer (sockets, framing primitives, SSL, HTTP-tunnel)
|
|
com.informix.jdbc # JDBC API surface: Driver, Connection, Statement, ResultSet, type wrappers
|
|
com.informix.jdbc.types # JDBC type-wrapper sub-types
|
|
com.informix.jdbc.udt # User-defined type support
|
|
com.informix.jdbcx # XA / DataSource / ConnectionPool extensions
|
|
com.informix.jns # Java Naming Service (sqlhosts lookup)
|
|
com.informix.judr # Java User-Defined Routines
|
|
com.informix.lang # Encoding/decoding bridge between Java types and Informix wire types
|
|
com.informix.smartTrigger # Smart-trigger event subscription
|
|
com.informix.types # Informix-side type system (Interval, Decimal, etc.)
|
|
com.informix.util # Tracing, error messages, properties
|
|
org.bson.* # MongoDB BSON support — ignore for SQLI work
|
|
```
|
|
|
|
**For SQLI wire-protocol implementation, only `com.informix.asf`, `com.informix.jdbc` (selected files), `com.informix.lang`, and `com.informix.util.IfxErrMsg` matter.** Everything else is JDBC API surface, ORM helpers, or unrelated bundles.
|
|
|
|
---
|
|
|
|
## Class index — wire-protocol concern → class
|
|
|
|
### Wire transport (the layer we're rebuilding in `_socket.py` + `_protocol.py`)
|
|
|
|
| Concern | Class | Path | Notes |
|
|
|---------|-------|------|-------|
|
|
| Raw socket lifecycle, SSL, login orchestration | `com.informix.asf.Connection` | `build/jdbc-src/com/informix/asf/Connection.java` (1228 LOC) | The wire-level connection. Owns `Socket asfSocket`, the buffered streams, `IfxDataInputStream/OutputStream`. This is what our `connections.py` layer maps to (just the socket+framing parts; SQL state lives a layer up). |
|
|
| Wire write primitives | `com.informix.asf.IfxDataOutputStream` | `…/asf/IfxDataOutputStream.java` (205 LOC) | `writeShort`, `writeInt`, `writeChar`, `writeDate`, `writeDateTime`, `writeDecimal`, `writeReal`, `writeDouble`, `writeSmallInt`, `writeLongInt`, `writeLongBigint`, `writePadded` (16-bit alignment). |
|
|
| Wire read primitives | `com.informix.asf.IfxDataInputStream` | `…/asf/IfxDataInputStream.java` (235 LOC) | Mirror of the above: `readShort`, `readInt`, `readChar` (length-prefixed string), `readDate`, `readDateTime`, `readDecimal`, `readReal`, `readDouble`, `readSmallInt`, `readLongInt`, `readLongBigint`, `readPadded`. |
|
|
| Protocol tracing (logging hook) | `com.informix.asf.SqliDbg` | `…/asf/SqliDbg.java` (135 LOC) | Records C2S / S2C transitions. Worth reading to learn which fields IBM thinks are interesting enough to log. |
|
|
| Debug-instrumented streams | `com.informix.asf.IfxDebugDataInputStream` / `OutputStream` | `…/asf/IfxDebug*.java` | Subclasses of the regular streams that emit trace records. Used when `SQLITRACEFILE` opt-prop is set. |
|
|
| HTTP-tunneled SQLI | `com.informix.asf.HttpConnection`, `HttpBufferedInputStream`, `HttpBufferedOutputStream` | `…/asf/Http*.java` | SQLI-over-HTTP for proxy/firewall traversal. **Phase 6+ at the earliest. Skip for MVP.** |
|
|
|
|
### Type encoding/decoding (JavaToIfx ↔ IfxToJava)
|
|
|
|
| Concern | Class | Path | Notes |
|
|
|---------|-------|------|-------|
|
|
| Java→wire encoders | `com.informix.lang.JavaToIfxType` | `…/lang/JavaToIfxType.java` | `JavaToIfxInt(int)` → 4-byte BE; `JavaToIfxSmallInt(short)` → 2-byte BE; `JavaToIfxLongBigInt(long)` → 8-byte BE; `JavaToIfxLongInt(long)` → 10-byte legacy variable-numeric (skip MVP); `JavaToIfxChar(String)` length-prefixed; `JavaToIfxDate`, `JavaToIfxDateTime`, `JavaToIfxDecimal`, `JavaToIfxReal`, `JavaToIfxDouble`. |
|
|
| Wire→Java decoders | `com.informix.lang.IfxToJavaType` | `…/lang/IfxToJavaType.java` | Mirror of the above. |
|
|
| IDS type metadata / type codes | `com.informix.lang.IfxTypes` | `…/lang/IfxTypes.java` | Constants for the IDS internal type IDs. The other half of the answer to "what's in column descriptors". |
|
|
| INTERVAL day-fraction / year-month structures | `com.informix.lang.IntervalDF`, `IntervalYM`, `Interval` | `…/lang/Interval*.java` | Phase 6+. |
|
|
|
|
### SQLI protocol (the layer we're rebuilding in `connections.py` + `cursors.py`)
|
|
|
|
| Concern | Class | Path | Notes |
|
|
|---------|-------|------|-------|
|
|
| Protocol contract | `com.informix.jdbc.IfxProtocol` (interface) | `…/jdbc/IfxProtocol.java` (146 LOC) | 50-method interface — read this FIRST to understand the protocol's "vocabulary" without drowning in implementation. Methods include `executeBegin/Commit/Rollback/Savepoint`, `executeVersion`, `executeProtocols`, `handlePAMAuthentication`, `executeOpenDatabase`, `executeCommand`, `executePrepare`, `executeExecute`, `executeFetchBlob`, `executeReadSmBlob`, `executeFastPath`, `handlePrivateServerExchange`. |
|
|
| SQLI protocol implementation | `com.informix.jdbc.IfxSqli` | `…/jdbc/IfxSqli.java` (6501 LOC) | The concrete `IfxProtocol` impl. Owns `IfxDataInputStream is` / `IfxDataOutputStream os` (inherited from `IfxSqliConnect`). Search for `os.writeShort(...)` to find every message-emit site. |
|
|
| Connection state machine + login orchestration | `com.informix.jdbc.IfxSqliConnect` | `…/jdbc/IfxSqliConnect.java` (5029 LOC) | Holds the `com.informix.asf.Connection`, owns the high-level connection state. Exposes `IfmxConnection`. |
|
|
| Message-type tag enumeration | `com.informix.jdbc.IfxMessageTypes` | `…/jdbc/IfxMessageTypes.java` (163 LOC) | All 142+ SQLI message type constants. **Goldmine.** See "Message type tag table" in `PROTOCOL_NOTES.md`. |
|
|
| JDBC Driver entry point | `com.informix.jdbc.IfxDriver` | `…/jdbc/IfxDriver.java` (584 LOC) | URL parsing, property handling, `Driver.connect()` impl. Useful for understanding what opt-props exist and which ones affect protocol behavior. |
|
|
| Connection extension interface | `com.informix.jdbc.IfmxConnection` (interface) | `…/jdbc/IfmxConnection.java` | Adds Informix-specific methods to `java.sql.Connection`: UDT info, HDR, `scrubConnection()` for pool reuse, `IFX_USEPUT`, prepared-statement cache. |
|
|
|
|
### Auth handlers
|
|
|
|
| Concern | Class | Notes |
|
|
|---------|-------|-------|
|
|
| Plain-password auth | inline in `Connection.encodeAscBinary()` | Username + password are written into the binary login PDU directly. No separate auth round-trip. **MVP target.** |
|
|
| Legacy text-mode auth (`-pPASSWORD` argv) | `Connection.EncodeAscString()` | Triggered when `capabilities == 0`. Emits literal `sqlexec USER -pPASSWORD VERSION SERIAL -dDB -fIEEEM ` argv string. Skip MVP. |
|
|
| PAM challenge/response | `IfmxPAM`, `IfxPAMChallenge`, `IfxPAMResponse`; `IfxSqli.handlePAMAuthentication(String)` | Triggered by server-initiated `SQ_CHALLENGE=129` → client replies with `SQ_RESPONSE=130`. **Phase 6+.** |
|
|
| Trusted Context | flag in `encodeAscBinary` (option bit `ASF_TRUSTCTXT = 0x4000000` in stmtoptions int) | Phase 6+. |
|
|
| GSSAPI / Kerberos | not directly visible in `Connection.java`; likely handled via JCE provider plumbing | Phase 6+ if ever. |
|
|
| **CSM is removed** | `Connection.getOptProperties()` throws `"CSM Encryption is no longer supported"` if `SECURITY` or `CSM` is set | Confirmed dead. Cross off forever. |
|
|
| SSL / TLS | inline in `Connection.openSocket()` | Wraps `Socket` with `SSLSocket`. Default protocols: TLSv1.3, TLSv1.2, TLSv1.1, TLSv1 (Java 11+). **Phase 6+.** |
|
|
|
|
### Errors
|
|
|
|
| Concern | Class | Notes |
|
|
|---------|-------|-------|
|
|
| Error code → message text | `com.informix.util.IfxErrMsg` | Maps SQLCODE to localized text. Used to construct exceptions and warnings. The `Message` CLI tool (`com.informix.jdbc.Message`) is just a thin wrapper. |
|
|
| Warning code → message text | `com.informix.util.IfxWarnMsg` | Same, for warnings. |
|
|
| ASF-level (transport) exceptions | `com.informix.asf.IfxASFException`, `IfxASFRemoteException` | Network / login-rejection errors. Distinct from SQL-level exceptions. |
|
|
| Tracing | `com.informix.util.Trace`, `TraceFlag` | Used throughout. |
|
|
|
|
### Stuff to ignore
|
|
|
|
- `com.informix.jdbc.types.*`, `com.informix.jdbc.udt.*` — JDBC API helpers, not protocol
|
|
- `com.informix.jdbcx.*` — DataSource/XA/Pool wrappers; sit ABOVE the protocol layer
|
|
- `com.informix.jns.*` — sqlhosts lookup; not relevant when we just connect to `host:port` directly
|
|
- `com.informix.judr.*` — Java UDR support; not protocol
|
|
- `com.informix.smartTrigger.*` — event-subscription feature; not MVP
|
|
- `com.informix.jdbc.IfxBlob`, `IfxClob`, `IfxLob*`, `IfxSmBlob`, `IfxSmartLobOutputStream` — large object support; Phase 6+
|
|
- `org.bson.*` — bundled MongoDB BSON; for the JSON/BSON column type. Phase 6+ at best
|
|
- `com.informix.jdbc.IfxBSONObject`, `IfxJSON`, `IfxImpExp` — BSON/JSON wrappers and import/export utilities
|
|
|
|
---
|
|
|
|
## Method-level pointers (specific Java methods → wire effect)
|
|
|
|
> Format: `Class#method() → wire bytes emitted/consumed`. Filled in as we read deeper.
|
|
|
|
### Connection / login
|
|
- `com.informix.asf.Connection#openSocket()` → opens the TCP (or SSL) socket to `ipAddr:PortNumber`, sets TCP_NODELAY, optional KEEPALIVE.
|
|
- `com.informix.asf.Connection#sendConnectionRequest(...)` → emits the binary login PDU (`encodeAscBinary` path) or legacy text login (`EncodeAscString` path).
|
|
- `com.informix.asf.Connection#encodeAscBinary(...)` → emits the binary login PDU. **See `PROTOCOL_NOTES.md §2 Login Sequence` for the byte-by-byte breakdown.** Markers used: 100, 101, 104, 106, 107, 108, 116, 127.
|
|
- `com.informix.asf.Connection#EncodeSLheader(o, pfPDUsize, slType, slAttribute, slOptions)` → 6-byte SL header preceding the binary login: `[short totalSize][byte slType][byte slAttribute][short slOptions]`.
|
|
- `com.informix.asf.Connection#EncodeAscString(...)` → emits the legacy text login: `"sqlexec USER -pPASSWORD VERSION SERIAL -dDB -fIEEEM "`.
|
|
- `com.informix.asf.Connection#recvConnectionResponse()` → reads `[short length][byte SLType][skipBytes 3][markers 100,101][...]` → dispatches to `DecodeAscBinary` / `DecodeAscString`.
|
|
- `com.informix.asf.Connection#DecodeAscBinary(in)` → reads server response: VersionNumber, SerialNumber, ApplidName, Cap_1, Cap_2, Cap_3, then a switch on a marker (102=SQ_ASCINITRESP, 103=redirect, 127=SQ_ASCEOT clean).
|
|
- `com.informix.asf.Connection#disconnectOrderly()` → sends bare `[short SQ_EXIT=56]`, expects server to echo back `[short 56]` or `[short 12=SQ_EOT]`. May receive interleaved `[short 99=SQ_XACTSTAT]` mid-stream.
|
|
|
|
### Type encoding
|
|
- `com.informix.lang.JavaToIfxType#JavaToIfxInt(int)` → 4-byte big-endian.
|
|
- `com.informix.lang.JavaToIfxType#JavaToIfxSmallInt(short)` → 2-byte big-endian.
|
|
- `com.informix.lang.JavaToIfxType#JavaToIfxLongBigInt(long)` → 8-byte big-endian (BIGINT type).
|
|
- `com.informix.lang.JavaToIfxType#JavaToIfxChar(String)` → returns `[short length+1][bytes][0x00 nul terminator]`. The `+1` accounts for the trailing nul.
|
|
- `com.informix.asf.IfxDataOutputStream#writePadded(byte[])` → write bytes, then write a 0x00 byte if length is odd. **The 16-bit-alignment requirement.**
|
|
|
|
### Disconnect
|
|
- `com.informix.asf.Connection#disconnectOrderly()` (above)
|
|
- Bare `[short 56]` is the only message the client emits; bare `[short 56]` or `[short 12]` is the response. No header.
|
|
|
|
---
|
|
|
|
## Useful greps
|
|
|
|
```bash
|
|
# Find every wire-emit site in IfxSqli.java (writeShort calls reveal message tags being sent)
|
|
grep -nE 'os\.writeShort\(' build/jdbc-src/com/informix/jdbc/IfxSqli.java
|
|
|
|
# Find every wire-read site
|
|
grep -nE '\.readShort\(\)' build/jdbc-src/com/informix/jdbc/IfxSqli.java
|
|
|
|
# Find login state-machine logic
|
|
grep -nE 'executeOpenDatabase|executeVersion|executeProtocols|handlePAM|handlePrivate' build/jdbc-src/com/informix/jdbc/IfxSqli.java
|
|
|
|
# Find type-codec dispatch
|
|
grep -nE 'switch.*[Cc]olType|case.*IfxTypes\.' build/jdbc-src/com/informix/jdbc/IfxSqli.java
|
|
|
|
# Authentication strings
|
|
grep -rln 'OBFUSCATE\|PWDOBFUSCATION\|GSS\|KERBEROS' build/jdbc-src/
|
|
|
|
# SQLSTATE / error mapping
|
|
grep -rln 'SQLSTATE' build/jdbc-src/
|
|
```
|