Explicit IPv6 addresses for mysql and pgsql
authorJeremy Harris <jgh146exb@wizmail.org>
Thu, 14 Nov 2024 23:57:49 +0000 (23:57 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Thu, 14 Nov 2024 23:57:49 +0000 (23:57 +0000)
doc/doc-docbook/spec.xfpt
doc/doc-txt/NewStuff
src/src/lookups/mysql.c
src/src/lookups/pgsql.c
test/scripts/2610-MySQL/2610
test/scripts/2620-Postgresql/2620
test/stderr/2610
test/stderr/2620
test/stdout/2610
test/stdout/2620

index 6aa1604a6942a8900dc2029dc8d5eebee1459069..8674cfa430cd97a4f42bfadc9279a05e04419d48 100644 (file)
@@ -8261,12 +8261,21 @@ An option group name for MySQL option files can be specified in square brackets;
 the default value is &"exim"&.
 The full syntax of each item in &%mysql_servers%& is:
 .display
 the default value is &"exim"&.
 The full syntax of each item in &%mysql_servers%& is:
 .display
-<&'hostname'&>::<&'port'&>(<&'socket name'&>)[<&'option group'&>]/&&&
-  <&'database'&>/<&'user'&>/<&'password'&>
+<&'hostspec'&><&'portspec'&>(<&'socket name'&>)[<&'option group'&>]/&&&
+   <&'database'&>/<&'user'&>/<&'password'&>
 .endd
 Any of the four sub-parts of the first field can be omitted. For normal use on
 the local host it can be left blank or set to just &"localhost"&.
 
 .endd
 Any of the four sub-parts of the first field can be omitted. For normal use on
 the local host it can be left blank or set to just &"localhost"&.
 
+.new
+A &'hostspec'& can be a hostname, an IPv4 address or an IPv6 address.
+For the latter, a &'portspec'& is a dot followed by a port number;
+for the other two a &'portspec'& is a colon followed by a port number.
+.wen
+
+Note that the default list-separator for the list of servers is a colon so
+(unless that is changed) all colons in list items must be doubled.
+
 No database need be supplied &-- but if it is absent here, it must be given in
 the queries.
 
 No database need be supplied &-- but if it is absent here, it must be given in
 the queries.
 
@@ -8282,6 +8291,10 @@ parameters for the connection.
 
 
 .subsection "Special PostgreSQL features" SECID74
 
 
 .subsection "Special PostgreSQL features" SECID74
+.new
+The &'hostspec'& for PostgreSQL follows the same rules as for MySQL above.
+.wen
+
 PostgreSQL lookups can also use Unix domain socket connections to the database.
 This is usually faster and costs less CPU time than a TCP/IP connection.
 However it can be used only if the mail server runs on the same machine as the
 PostgreSQL lookups can also use Unix domain socket connections to the database.
 This is usually faster and costs less CPU time than a TCP/IP connection.
 However it can be used only if the mail server runs on the same machine as the
index cdcb11bb8cdf31f41f405e93f48dc0099cc0a523..2cce3f53393f9a805425a287c3dc5742f9bd17ec 100644 (file)
@@ -28,6 +28,8 @@ Version 4.98
 
  8. ATRN provider support
 
 
  8. ATRN provider support
 
+ 9. IPv6 address support for mysql and pgsql lookups
+
 Version 4.98
 ------------
  1. The dkim_status ACL condition may now be used in data ACLs
 Version 4.98
 ------------
  1. The dkim_status ACL condition may now be used in data ACLs
index 6b4638f709a83944940f7b38b81f7542919c06d0..ff19f5c802f642bc41481fec925cf4e41d327981 100644 (file)
@@ -207,11 +207,18 @@ if (!cn)
     *p = 0;
     }
 
     *p = 0;
     }
 
-  if ((p = Ustrchr(sdata[0], ':')))
-    {
-    *p++ = 0;
-    port = Uatoi(p);
-    }
+  /* If there is a colon (":") it could be a port number after an ipv4 or
+  hostname, or could be an ipv6. The latter must have at least two colons,
+  and we look instead for a period ("."). */
+
+  if ((p = Ustrrchr(sdata[0], ':')))
+    if (  Ustrchr(sdata[0], ':') == p          /* only one colon */
+       || (p = Ustrrchr(sdata[0], '.'))                /* >1 colon, and a period */
+       )
+      {
+      *p++ = 0;
+      port = Uatoi(p);
+      }
 
   if (Ustrchr(sdata[0], '/'))
     {
 
   if (Ustrchr(sdata[0], '/'))
     {
index 9d97afca9cecc6e3360b0adbb8661f2d03f93a32..c0e2ada5180659d9ed88879c26946f54067c39c7 100644 (file)
@@ -146,7 +146,7 @@ for (int i = 2; i >= 0; i--)
   if (!pp)
     {
     *errmsg = string_sprintf("incomplete pgSQL server data: %s",
   if (!pp)
     {
     *errmsg = string_sprintf("incomplete pgSQL server data: %s",
-      (i == 2)? server : server_copy);
+      i == 2 ? server : server_copy);
     *defer_break = TRUE;
     return DEFER;
     }
     *defer_break = TRUE;
     return DEFER;
     }
@@ -210,12 +210,21 @@ if (!cn)
 
   else
     {
 
   else
     {
-    uschar *p;
-    if ((p = Ustrchr(server, ':')))
-      {
-      *p++ = 0;
-      port = p;
-      }
+    uschar * p;
+
+    /* If there is a colon (":") it could be a port number after an ipv4 or
+    hostname, or could be an ipv6. The latter must have at least two colons,
+    and we look instead for a period (".").  We assume a hostname never
+    contains a colon. */
+
+    if ((p = Ustrrchr(server, ':')))
+      if (  Ustrchr(server, ':') == p          /* only one colon */
+        || (p = Ustrrchr(server, '.'))         /* >1 colon, and a period */
+        )
+       {
+       *p++ = 0;
+       port = p;
+       }
 
     if (Ustrchr(server, '/'))
       {
 
     if (Ustrchr(server, '/'))
       {
index 597504a59f459a146e93da9afbe697350fa7dfc3..edefd38b9bb93f3a57a59f2ee97a89d824cd43a4 100644 (file)
@@ -74,6 +74,8 @@ ${lookup mysql {select * from them where id='nlonly';}}
 ${lookup mysql {servers=x:127.0.0.1::PORT_N; select name from them where id='ph10';}}
 ${lookup mysql {servers=127.0.0.1::PORT_N:x; select name from them where id='ph10';}}
 ${lookup mysql {servers=127.0.0.1::PORT_N/test/root/:x; select name from them where id='ph10';}}
 ${lookup mysql {servers=x:127.0.0.1::PORT_N; select name from them where id='ph10';}}
 ${lookup mysql {servers=127.0.0.1::PORT_N:x; select name from them where id='ph10';}}
 ${lookup mysql {servers=127.0.0.1::PORT_N/test/root/:x; select name from them where id='ph10';}}
+oldsyntax ipv6: ${lookup mysql {servers=<!::1.PORT_N/test/root/pass!x; select name from them where id='ph10';}}
+newsyntax ipv6: ${lookup mysql,servers=<!::1.PORT_N/test/root/pass!x {select name from them where id='ph10';}}
 ${lookup mysql {servers=HOSTIPV4::PORT_N/test/root/:127.0.0.1::PORT_N; select name from them where id='ph10';}}
 ${lookup mysql {servers=localhost(DIR/mysql/sock)/test/root/pass; select name from them where id='ph10';}}
 x
 ${lookup mysql {servers=HOSTIPV4::PORT_N/test/root/:127.0.0.1::PORT_N; select name from them where id='ph10';}}
 ${lookup mysql {servers=localhost(DIR/mysql/sock)/test/root/pass; select name from them where id='ph10';}}
 x
index bad032b30f99afebfd5b728accfd802c7f6f29ff..ff2abb7e9cc5af76aeeadbbe9e7d4670a3362c1b 100644 (file)
@@ -50,7 +50,10 @@ ${lookup pgsql {select * from them where id='tab';}}
 ${lookup pgsql {select * from them where name='${quote_pgsql:'stquot}';}}
 ${lookup pgsql {servers=x:localhost; select name from them where id='ph10';}}
 ${lookup pgsql {servers=localhost::PORT_N:x; select name from them where id='ph10';}}
 ${lookup pgsql {select * from them where name='${quote_pgsql:'stquot}';}}
 ${lookup pgsql {servers=x:localhost; select name from them where id='ph10';}}
 ${lookup pgsql {servers=localhost::PORT_N:x; select name from them where id='ph10';}}
-${lookup pgsql {servers=localhost::PORT_N/test/CALLER/:x; select name from them where id='ph10';}}
+name: ${lookup pgsql {servers=localhost::PORT_N/test/CALLER/:x; select name from them where id='ph10';}}
+ipv4: ${lookup pgsql {servers=127.0.0.1::PORT_N/test/CALLER/:x; select name from them where id='ph10';}}
+oldsyntax ipv6: ${lookup pgsql {servers=<!::1.PORT_N/test/CALLER/!x; select name from them where id='ph10';}}
+newsyntax ipv6: ${lookup pgsql,servers=<!::1.PORT_N/test/CALLER/!x { select name from them where id='ph10';}}
 ${lookup pgsql {servers=(DIR/pgsql/.s.PGSQL.PORT_N)/test/CALLER/:x; select name from them where id='ph10';}}
 x
 ${lookup pgsql {SELECT name FROM them WHERE id IN ('ph10', 'aaaa');}}
 ${lookup pgsql {servers=(DIR/pgsql/.s.PGSQL.PORT_N)/test/CALLER/:x; select name from them where id='ph10';}}
 x
 ${lookup pgsql {SELECT name FROM them WHERE id IN ('ph10', 'aaaa');}}
index 0addebc6981c273891731b233ede617b6b4ef6ac..dc54f12bc6ff6d494bb9666f0429d3a0b0075717 100644 (file)
@@ -170,6 +170,33 @@ LOG: MAIN
  MYSQL using cached connection for 127.0.0.1:PORT_N/test/root
  creating new cache entry
  lookup yielded: Philip░Hazel
  MYSQL using cached connection for 127.0.0.1:PORT_N/test/root
  creating new cache entry
  lookup yielded: Philip░Hazel
+ search_open: mysql "NULL"
+   cached open
+ search_find: file="NULL"
+   key="servers=<!::1.1223/test/root/pass!x; select name from them where id='ph10';" partial=-1 affix=NULL starflags=0 opts=NULL
+ LRU list:
+ internal_search_find: file="NULL"
+   type=mysql key="servers=<!::1.1223/test/root/pass!x; select name from them where id='ph10';" opts=NULL
+ database lookup required for servers=<!::1.1223/test/root/pass!x; select name from them where id='ph10';
+ MySQL query: "servers=<!::1.1223/test/root/pass!x; select name from them where id='ph10';" opts 'NULL'
+LOG: MAIN
+  Exim configuration error in line 14 of -be stdin:
+  WARNING: obsolete syntax used for lookup
+ MYSQL new connection: host=::1 port=PORT_N socket=NULL database=test user=root
+ creating new cache entry
+ lookup yielded: Philip░Hazel
+ search_open: mysql "NULL"
+   cached open
+ search_find: file="NULL"
+   key="select name from them where id='ph10';" partial=-1 affix=NULL starflags=0 opts="servers=<!::1.1223/test/root/pass!x"
+ LRU list:
+ internal_search_find: file="NULL"
+   type=mysql key="select name from them where id='ph10';" opts="servers=<!::1.1223/test/root/pass!x"
+ database lookup required for select name from them where id='ph10';
+ MySQL query: "select name from them where id='ph10';" opts 'servers=<!::1.1223/test/root/pass!x'
+ MYSQL using cached connection for ::1.1223/test/root
+ creating new cache entry
+ lookup yielded: Philip░Hazel
  search_open: mysql "NULL"
    cached open
  search_find: file="NULL"
  search_open: mysql "NULL"
    cached open
  search_find: file="NULL"
@@ -180,7 +207,7 @@ LOG: MAIN
  database lookup required for servers=ip4.ip4.ip4.ip4::1223/test/root/:127.0.0.1::PORT_N; select name from them where id='ph10';
  MySQL query: "servers=ip4.ip4.ip4.ip4::1223/test/root/:127.0.0.1::PORT_N; select name from them where id='ph10';" opts 'NULL'
 LOG: MAIN
  database lookup required for servers=ip4.ip4.ip4.ip4::1223/test/root/:127.0.0.1::PORT_N; select name from them where id='ph10';
  MySQL query: "servers=ip4.ip4.ip4.ip4::1223/test/root/:127.0.0.1::PORT_N; select name from them where id='ph10';" opts 'NULL'
 LOG: MAIN
-  Exim configuration error in line 14 of -be stdin:
+  Exim configuration error in line 16 of -be stdin:
   WARNING: obsolete syntax used for lookup
  MYSQL new connection: host=ip4.ip4.ip4.ip4 port=PORT_N socket=NULL database=test user=root
  creating new cache entry
   WARNING: obsolete syntax used for lookup
  MYSQL new connection: host=ip4.ip4.ip4.ip4 port=PORT_N socket=NULL database=test user=root
  creating new cache entry
@@ -195,7 +222,7 @@ LOG: MAIN
  database lookup required for servers=localhost(TESTSUITE/mysql/sock)/test/root/pass; select name from them where id='ph10';
  MySQL query: "servers=localhost(TESTSUITE/mysql/sock)/test/root/pass; select name from them where id='ph10';" opts 'NULL'
 LOG: MAIN
  database lookup required for servers=localhost(TESTSUITE/mysql/sock)/test/root/pass; select name from them where id='ph10';
  MySQL query: "servers=localhost(TESTSUITE/mysql/sock)/test/root/pass; select name from them where id='ph10';" opts 'NULL'
 LOG: MAIN
-  Exim configuration error in line 15 of -be stdin:
+  Exim configuration error in line 17 of -be stdin:
   WARNING: obsolete syntax used for lookup
  MYSQL new connection: host=localhost port=0 socket=TESTSUITE/mysql/sock database=test user=root
  creating new cache entry
   WARNING: obsolete syntax used for lookup
  MYSQL new connection: host=localhost port=0 socket=TESTSUITE/mysql/sock database=test user=root
  creating new cache entry
@@ -242,6 +269,7 @@ LOG: MAIN
 search_tidyup called
 close MYSQL connection: localhost(TESTSUITE/mysql/sock)/test/root
 close MYSQL connection: ip4.ip4.ip4.ip4:1223/test/root
 search_tidyup called
 close MYSQL connection: localhost(TESTSUITE/mysql/sock)/test/root
 close MYSQL connection: ip4.ip4.ip4.ip4:1223/test/root
+close MYSQL connection: ::1.1223/test/root
 close MYSQL connection: 127.0.0.1:PORT_N/test/root
 >>>>>>>>>>>>>>>> Exim pid=p1234 (fresh-exec) terminating with rc=0 >>>>>>>>>>>>>>>>
 01:01:01 p1235  Exim version x.yz uid=CALLER_UID gid=CALLER_GID pid=p1235 D=fff9ffff
 close MYSQL connection: 127.0.0.1:PORT_N/test/root
 >>>>>>>>>>>>>>>> Exim pid=p1234 (fresh-exec) terminating with rc=0 >>>>>>>>>>>>>>>>
 01:01:01 p1235  Exim version x.yz uid=CALLER_UID gid=CALLER_GID pid=p1235 D=fff9ffff
index fc3e76f2e17a720d676cebf3fb18cd6a0bffee16..fe745935632919eaa928bb675651845e1cacdf72 100644 (file)
@@ -168,6 +168,48 @@ LOG: MAIN
  PGSQL using cached connection for localhost:PORT_N/test/CALLER
  creating new cache entry
  lookup yielded: Philip░Hazel
  PGSQL using cached connection for localhost:PORT_N/test/CALLER
  creating new cache entry
  lookup yielded: Philip░Hazel
+ search_open: pgsql "NULL"
+   cached open
+ search_find: file="NULL"
+   key="servers=127.0.0.1::PORT_N/test/CALLER/:x; select name from them where id='ph10';" partial=-1 affix=NULL starflags=0 opts=NULL
+ LRU list:
+ internal_search_find: file="NULL"
+   type=pgsql key="servers=127.0.0.1::PORT_N/test/CALLER/:x; select name from them where id='ph10';" opts=NULL
+ database lookup required for servers=127.0.0.1::PORT_N/test/CALLER/:x; select name from them where id='ph10';
+ PostgreSQL query: "servers=127.0.0.1::PORT_N/test/CALLER/:x; select name from them where id='ph10';" opts 'NULL'
+LOG: MAIN
+  Exim configuration error in line 14 of -be stdin:
+  WARNING: obsolete syntax used for lookup
+ PGSQL new connection: host=127.0.0.1 port=PORT_N database=test user=CALLER
+ creating new cache entry
+ lookup yielded: Philip░Hazel
+ search_open: pgsql "NULL"
+   cached open
+ search_find: file="NULL"
+   key="servers=<!::1.1223/test/CALLER/!x; select name from them where id='ph10';" partial=-1 affix=NULL starflags=0 opts=NULL
+ LRU list:
+ internal_search_find: file="NULL"
+   type=pgsql key="servers=<!::1.1223/test/CALLER/!x; select name from them where id='ph10';" opts=NULL
+ database lookup required for servers=<!::1.1223/test/CALLER/!x; select name from them where id='ph10';
+ PostgreSQL query: "servers=<!::1.1223/test/CALLER/!x; select name from them where id='ph10';" opts 'NULL'
+LOG: MAIN
+  Exim configuration error in line 15 of -be stdin:
+  WARNING: obsolete syntax used for lookup
+ PGSQL new connection: host=::1 port=PORT_N database=test user=CALLER
+ creating new cache entry
+ lookup yielded: Philip░Hazel
+ search_open: pgsql "NULL"
+   cached open
+ search_find: file="NULL"
+   key="select name from them where id='ph10';" partial=-1 affix=NULL starflags=0 opts="servers=<!::1.1223/test/CALLER/!x"
+ LRU list:
+ internal_search_find: file="NULL"
+   type=pgsql key="select name from them where id='ph10';" opts="servers=<!::1.1223/test/CALLER/!x"
+ database lookup required for select name from them where id='ph10';
+ PostgreSQL query: "select name from them where id='ph10';" opts 'servers=<!::1.1223/test/CALLER/!x'
+ PGSQL using cached connection for ::1.1223/test/CALLER
+ creating new cache entry
+ lookup yielded: Philip░Hazel
  search_open: pgsql "NULL"
    cached open
  search_find: file="NULL"
  search_open: pgsql "NULL"
    cached open
  search_find: file="NULL"
@@ -178,7 +220,7 @@ LOG: MAIN
  database lookup required for servers=(TESTSUITE/pgsql/.s.PGSQL.1223)/test/CALLER/:x; select name from them where id='ph10';
  PostgreSQL query: "servers=(TESTSUITE/pgsql/.s.PGSQL.1223)/test/CALLER/:x; select name from them where id='ph10';" opts 'NULL'
 LOG: MAIN
  database lookup required for servers=(TESTSUITE/pgsql/.s.PGSQL.1223)/test/CALLER/:x; select name from them where id='ph10';
  PostgreSQL query: "servers=(TESTSUITE/pgsql/.s.PGSQL.1223)/test/CALLER/:x; select name from them where id='ph10';" opts 'NULL'
 LOG: MAIN
-  Exim configuration error in line 14 of -be stdin:
+  Exim configuration error in line 17 of -be stdin:
   WARNING: obsolete syntax used for lookup
  PGSQL new connection: socket=TESTSUITE/pgsql/.s.PGSQL.1223 database=test user=CALLER
  creating new cache entry
   WARNING: obsolete syntax used for lookup
  PGSQL new connection: socket=TESTSUITE/pgsql/.s.PGSQL.1223 database=test user=CALLER
  creating new cache entry
@@ -224,6 +266,8 @@ LOG: MAIN
  lookup yielded: 1
 search_tidyup called
 close PGSQL connection: (TESTSUITE/pgsql/.s.PGSQL.1223)/test/CALLER
  lookup yielded: 1
 search_tidyup called
 close PGSQL connection: (TESTSUITE/pgsql/.s.PGSQL.1223)/test/CALLER
+close PGSQL connection: ::1.1223/test/CALLER
+close PGSQL connection: 127.0.0.1:PORT_N/test/CALLER
 close PGSQL connection: localhost:PORT_N/test/CALLER
 >>>>>>>>>>>>>>>> Exim pid=p1235 (fresh-exec) terminating with rc=0 >>>>>>>>>>>>>>>>
 Exim version x.yz ....
 close PGSQL connection: localhost:PORT_N/test/CALLER
 >>>>>>>>>>>>>>>> Exim pid=p1235 (fresh-exec) terminating with rc=0 >>>>>>>>>>>>>>>>
 Exim version x.yz ....
index 961928b8e1fc324a2f12906d9d372291f7c0c508..aeacedf4c2c0f4fc78f9bfd026b3f8b2932d7d68 100644 (file)
@@ -14,6 +14,8 @@
 > Failed: lookup of "servers=x:127.0.0.1::1223; select name from them where id='ph10';" gave DEFER: MySQL server "x" not found in mysql_servers
 > Philip Hazel
 > Philip Hazel
 > Failed: lookup of "servers=x:127.0.0.1::1223; select name from them where id='ph10';" gave DEFER: MySQL server "x" not found in mysql_servers
 > Philip Hazel
 > Philip Hazel
+> oldsyntax ipv6: Philip Hazel
+> newsyntax ipv6: Philip Hazel
 > Philip Hazel
 > Philip Hazel
 > x
 > Philip Hazel
 > Philip Hazel
 > x
index f0796ae6f894eae19c6c9cb48348352ca32851c2..c8fe17cce7f8cc32853e66b368ff00c062ce2c7d 100644 (file)
@@ -46,7 +46,10 @@ after" id=newline
 > name='stquot id=quote1 
 > Failed: lookup of "servers=x:localhost; select name from them where id='ph10';" gave DEFER: PostgreSQL server "x" not found in pgsql_servers
 > Philip Hazel
 > name='stquot id=quote1 
 > Failed: lookup of "servers=x:localhost; select name from them where id='ph10';" gave DEFER: PostgreSQL server "x" not found in pgsql_servers
 > Philip Hazel
-> Philip Hazel
+> name: Philip Hazel
+> ipv4: Philip Hazel
+> oldsyntax ipv6: Philip Hazel
+> newsyntax ipv6: Philip Hazel
 > Philip Hazel
 > x
 > Philip Hazel
 > Philip Hazel
 > x
 > Philip Hazel