diff --git a/lib/gat/gatcaddyfile/gattype.go b/lib/gat/gatcaddyfile/gattype.go
index 3b96dc9362e13baf888968a69beb34f65710671a..14186ad48db68aa8b19ddd587a42d3ccf82270b7 100644
--- a/lib/gat/gatcaddyfile/gattype.go
+++ b/lib/gat/gatcaddyfile/gattype.go
@@ -1,6 +1,8 @@
 package gatcaddyfile
 
 import (
+	"fmt"
+
 	"github.com/caddyserver/caddy/v2"
 	"github.com/caddyserver/caddy/v2/caddyconfig"
 	"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
@@ -25,6 +27,27 @@ func (ServerType) Setup(blocks []caddyfile.ServerBlock, m map[string]any) (*cadd
 
 		server.Match = MatcherFromConnectionStrings(block.Keys, &warnings)
 
+		for _, segment := range block.Segments {
+			d := caddyfile.NewDispenser(segment)
+			if !d.Next() {
+				continue
+			}
+			switch d.Val() {
+			case "pgbouncer":
+				var route gat.RouteConfig
+				if d.CountRemainingArgs() == 2 {
+					d.Next()
+					route.Match = MatcherFromConnectionString(d.Val(), &warnings)
+				}
+				// TODO(garet) read actual value
+				server.Routes = append(server.Routes, route)
+			case "discovery":
+				// TODO(garet)
+			default:
+				return nil, nil, fmt.Errorf("unknown directive: %s", d.Val())
+			}
+		}
+
 		app.Servers = append(app.Servers, server)
 	}
 
diff --git a/lib/gat/gatcaddyfile/matchers.go b/lib/gat/gatcaddyfile/matchers.go
index a85e141e4e1e9ff489e192582ae4f61dfb0ac1c4..a6c33a0a691e325f9d47ba32982730d44fa9d229 100644
--- a/lib/gat/gatcaddyfile/matchers.go
+++ b/lib/gat/gatcaddyfile/matchers.go
@@ -7,6 +7,7 @@ import (
 	"github.com/caddyserver/caddy/v2/caddyconfig"
 
 	"gfx.cafe/gfx/pggat/lib/gat/matchers"
+	"gfx.cafe/gfx/pggat/lib/util/strutil"
 )
 
 func MatcherFromConnectionStrings(strs []string, warnings *[]caddyconfig.Warning) json.RawMessage {
@@ -47,9 +48,9 @@ func MatcherFromConnectionString(str string, warnings *[]caddyconfig.Warning) js
 	var and matchers.And
 
 	var parametersString string
-	str, parametersString, _ = strings.Cut(str, "?")
+	str, parametersString, _ = strutil.CutRight(str, "?")
 
-	if parametersString != "" {
+	if parametersString != "" && parametersString != "*" {
 		var parameters matchers.StartupParameters
 		parameters.Parameters = make(map[string]string)
 		kvs := strings.Split(parametersString, "&")
@@ -69,8 +70,8 @@ func MatcherFromConnectionString(str string, warnings *[]caddyconfig.Warning) js
 	}
 
 	var database matchers.Database
-	str, database.Database, _ = strings.Cut(str, "/")
-	if database.Database != "" {
+	str, database.Database, _ = strutil.CutRight(str, "/")
+	if database.Database != "" && database.Database != "*" {
 		and.And = append(
 			and.And,
 			caddyconfig.JSONModuleObject(
@@ -82,16 +83,10 @@ func MatcherFromConnectionString(str string, warnings *[]caddyconfig.Warning) js
 		)
 	}
 
-	var address = matchers.LocalAddress{
-		Network: "tcp",
-	}
+	var address matchers.LocalAddress
 	var user matchers.User
-	var ok bool
-	user.User, address.Address, ok = strings.Cut(str, "@")
-	if !ok {
-		address.Address = user.User
-		user.User = ""
-	} else if user.User != "" {
+	user.User, address.Address, _ = strutil.CutLeft(str, "@")
+	if user.User != "" && user.User != "*" {
 		and.And = append(
 			and.And,
 			caddyconfig.JSONModuleObject(
@@ -102,7 +97,12 @@ func MatcherFromConnectionString(str string, warnings *[]caddyconfig.Warning) js
 			),
 		)
 	}
-	if address.Address != "" {
+	if address.Address != "" && address.Address != "*" {
+		if strings.HasPrefix(address.Address, "/") {
+			address.Network = "unix"
+		} else {
+			address.Network = "tcp"
+		}
 		and.And = append(
 			and.And,
 			caddyconfig.JSONModuleObject(
diff --git a/lib/gat/handlers/allowed_startup_parameters/module.go b/lib/gat/handlers/allowed_startup_parameters/module.go
index 5eeadc4ec642a0421f92f33e01e7fdd11c331d03..f23ab20e767f24769ecd06b515263126b18c929b 100644
--- a/lib/gat/handlers/allowed_startup_parameters/module.go
+++ b/lib/gat/handlers/allowed_startup_parameters/module.go
@@ -1,4 +1,4 @@
-package module
+package allowed_startup_parameters
 
 import (
 	"fmt"
diff --git a/lib/util/strutil/cut.go b/lib/util/strutil/cut.go
new file mode 100644
index 0000000000000000000000000000000000000000..d8798b33d244a0368bd6acd7b3557f2aa5dc3c57
--- /dev/null
+++ b/lib/util/strutil/cut.go
@@ -0,0 +1,21 @@
+package strutil
+
+import "strings"
+
+// CutLeft is similar to strings.Cut but it returns "", s, false if not found
+func CutLeft(s string, sep string) (before, after string, found bool) {
+	before, after, found = strings.Cut(s, sep)
+	if !found {
+		after = before
+		before = ""
+	}
+	return
+}
+
+// CutRight is similar to strings.Cut but it searches from the end first
+func CutRight(s string, sep string) (before, after string, found bool) {
+	if i := strings.LastIndex(s, sep); i >= 0 {
+		return s[:i], s[i+len(sep):], true
+	}
+	return s, "", false
+}