2015-02-11 1 views
0

Важное примечание. Был прорыв в Edit # 2 в конце, поэтому обязательно прочтите это.Почему драйвер PostgreSQL JDBC отправляет плохой заголовок пакета на сервер во время аутентификации?

Я в clojure, пытаясь использовать JDBC для подключения к нашей серверу PostgreSQL. Сервер использует pgBouncer.

Вот мои зависимости проекта:

:dependencies [[org.clojure/clojure "1.6.0"] 
       [org.clojure/java.jdbc "0.3.6"] 
       [org.postgresql/postgresql "9.4-1200-jdbc41"]] 

И вот мой код:

(ns pg-test.core 
    (:require [clojure.java.jdbc :as jdbc])) 

(def db 
    {:subprotocol "postgresql" 
    :subname "//the-server-name:the-port/db-name" 
    :sslmode "require" 
    :user "my-username" 
    :password "super-secret-password"}) 

(jdbc/query db ["SELECT 5"]) 

Когда я запускаю этот код, я получаю один из трех результатов:

  1. орга. postgresql.util.PSQLException: попытка подключения не удалась.
  2. org.postgresql.util.PSQLException: ОШИБКА: плохой заголовок пакета: '70'
  3. ОЧЕНЬ РАВНО (три раза сейчас, из сотен попыток), это действительно сработает! Она возвращает ({:?column? 5})

 

Что происходит? Почему эта работа иногда, но почти NEVER?

 

Мои настройки

  • OS X Yosemite (но я никогда не мог заставить его работать с моей виртуальной машине Ubuntu, либо.)
  • lein repl :headless :port 2358 с последующим cider-connect в Emacs.
  • Сервер Postgres 9.1.12

Edit # 2

Только узнал о возможности :loglevel 2. Это устанавливает его на уровень вывода «DEBUG», и я собрал еще несколько интересных данных. Вот результат:

21:45:34.921 (31) PostgreSQL 9.4 JDBC4.1 (build 1200) 
21:45:34.927 (31) Trying to establish a protocol version 3 connection to the-server-name:the-port 
21:45:35.020 (31) FE=> SSLRequest 
21:45:35.120 (31) <=BE SSLOk 
21:45:35.120 (31) converting regular socket connection to ssl 
21:45:35.324 (31) Receive Buffer Size is 131072 
21:45:35.324 (31) Send Buffer Size is 131136 
21:45:35.324 (31) FE=> StartupPacket(user=my-username, database=db-name, client_encoding=UTF8, DateStyle=ISO, TimeZone=America/Denver, extra_float_digits=2) 
21:45:35.435 (31) <=BE AuthenticationReqMD5(salt=f244b442) 
21:45:35.436 (31) FE=> Password(md5digest=md52e3d9f29d44d48ab19ef3469d54d50d1) 
21:45:35.520 (31) <=BE ErrorMessage(ERROR: bad packet header: '70') 

Затем дает следующую трассировку стека:

org.postgresql.util.PSQLException: ERROR: bad packet header: '70' 
    at org.postgresql.core.v3.ConnectionFactoryImpl.doAuthentication(ConnectionFactoryImpl.java:420) 
    at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:195) 
    at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:66) 
    at org.postgresql.jdbc2.AbstractJdbc2Connection.<init>(AbstractJdbc2Connection.java:127) 
    at org.postgresql.jdbc3.AbstractJdbc3Connection.<init>(AbstractJdbc3Connection.java:29) 
    at org.postgresql.jdbc3g.AbstractJdbc3gConnection.<init>(AbstractJdbc3gConnection.java:21) 
    at org.postgresql.jdbc4.AbstractJdbc4Connection.<init>(AbstractJdbc4Connection.java:41) 
    at org.postgresql.jdbc4.Jdbc4Connection.<init>(Jdbc4Connection.java:24) 
    at org.postgresql.Driver.makeConnection(Driver.java:414) 
    at org.postgresql.Driver.connect(Driver.java:282) 
    at java.sql.DriverManager.getConnection(DriverManager.java:571) 
    at java.sql.DriverManager.getConnection(DriverManager.java:187) 
    at clojure.java.jdbc$get_connection.invoke(jdbc.clj:255) 
    at clojure.java.jdbc$db_query_with_resultset.invoke(jdbc.clj:798) 
    at clojure.java.jdbc$query.doInvoke(jdbc.clj:832) 
    at clojure.lang.RestFn.invoke(RestFn.java:425) 
    at pg_test.core$eval4536.invoke(core.clj:14) 
    at clojure.lang.Compiler.eval(Compiler.java:6703) 
    at clojure.lang.Compiler.load(Compiler.java:7130) 
    at pg_test.core$eval4524.invoke(form-init6588155330850041472.clj:1) 
    at clojure.lang.Compiler.eval(Compiler.java:6703) 
    at clojure.lang.Compiler.eval(Compiler.java:6666) 
    at clojure.core$eval.invoke(core.clj:2927) 
    at clojure.main$repl$read_eval_print__6625$fn__6628.invoke(main.clj:239) 
    at clojure.main$repl$read_eval_print__6625.invoke(main.clj:239) 
    at clojure.main$repl$fn__6634.invoke(main.clj:257) 
    at clojure.main$repl.doInvoke(main.clj:257) 
    at clojure.lang.RestFn.invoke(RestFn.java:1523) 
    at clojure.tools.nrepl.middleware.interruptible_eval$evaluate$fn__592.invoke(interruptible_eval.clj:67) 
    at clojure.lang.AFn.applyToHelper(AFn.java:152) 
    at clojure.lang.AFn.applyTo(AFn.java:144) 
    at clojure.core$apply.invoke(core.clj:624) 
    at clojure.core$with_bindings_STAR_.doInvoke(core.clj:1862) 
    at clojure.lang.RestFn.invoke(RestFn.java:425) 
    at clojure.tools.nrepl.middleware.interruptible_eval$evaluate.invoke(interruptible_eval.clj:51) 
    at clojure.tools.nrepl.middleware.interruptible_eval$interruptible_eval$fn__634$fn__637.invoke(interruptible_eval.clj:183) 
    at clojure.tools.nrepl.middleware.interruptible_eval$run_next$fn__627.invoke(interruptible_eval.clj:152) 
    at clojure.lang.AFn.run(AFn.java:22) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
    at java.lang.Thread.run(Thread.java:745) 

Но это дает этот код ошибки!

SQLException: SQLState(08P01) 

который, согласно this website, означает «НАРУШЕНИЕ ПРОТОКОЛА».

Я искал google для нарушения протокола 08P01 и нашел this bug report для полностью несвязанного проекта на GitHub с заголовком «08P01 PROTOCOL VIOLATION» при попытке записать кодированные символы юникода в строковые поля ».

Итак, давайте посмотрим на то, что мы посылаем:

  • StartupPacket(user=my-username, database=db-name, client_encoding=UTF8, DateStyle=ISO, TimeZone=America/Denver, extra_float_digits=2) . Обратите внимание, что наша кодировка UTF8.
  • Затем мы отправляем Password(md5digest=md52e3d9f29d44d48ab19ef3469d54d50d1) , и сразу же получаем исключение «плохого заголовка пакета» 70 ».

Неужели UTF8 разрушает мою жизнь снова? Я думал, что мы оставили эти плохие дни позади нас так давно.

Так что теперь мне интересно, есть ли способ изменить клиентскую кодировку. Или, возможно, изменить используемый метод аутентификации.

+0

Это может быть также полезно знать, что программа PSQL клиент работает без сучка от моей машины. Это заставляет меня думать, что это какая-то странность jdbc, а не проблема с сетью. –

+0

Я просто попытался сделать это с чистой Java (т. Е. Не в Clojure.) Я получаю те же результаты. Удивительно, что pgBouncer не играет хорошо с JDBC. –

ответ

0

Работает ли он без SSL? Если да, можете ли вы убедиться, что вы не запускаете криптографически искалеченную версию вашей JVM? Я предполагаю, что JVM Oracles нуждается в экспортном ограничении шифрования JCE.

Сильное шифрование ОКА можно загрузить с http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html

1

По словам водителя PgJDBC «PgJDBC имеет дополнительные зависимости от других библиотек для некоторых функций. Эти библиотеки также должны быть на вашем пути к классам, если вы хотите использовать эти функции , если это не так, вы получите PSQLException во время выполнения, когда пытаетесь использовать функции с отсутствующими библиотеками ».

Некоторая зависимая или, возможно, собственная скомпилированная SSL-библиотека, скорее всего, отсутствует. Я понятия не имею, почему это иногда срабатывало на синей луне, если бы это было так.

https://github.com/pgjdbc/pgjdbc/blob/f96f6b3c0fdcb9c393b870b834adb1248f955cee/README.md#dependencies

+0

Ну, и это самая тревожная вещь для меня, что она работает иногда, хотя и очень редко. Это заставляет меня задаться вопросом, является ли это какой-то странной сетевой проблемой, но я понятия не имею, как я буду диагностировать это. –

+0

взгляните на Редактировать # 2. Проблема возникает сразу после отправки пароля (md5digest = md5blahblahblah). Может ли быть так, что соль, отправленная с сервера (каждый раз по разному), иногда приводит к серии байтов, которые DO закодированы правильно и разрешают соединение? –

0

This link к примеру Postgres соединения Heroku упоминает еще две пары ключ-значение,

:ssl true 

и

:sslfactory (when-not (:production environ/env) 
      "org.postgresql.ssl.NonValidatingFactory") 
+0

с использованием поставщика, не проверяющего достоверность, сообщит вам, что проблема заключается в отсутствии корневого сертификата или базы данных с использованием самоподписанного сертификата. В противном случае это даст вам небольшую информацию. Оставляя его, вы получаете практически тот же уровень безопасности, что и не используя SSL –

Смежные вопросы