(domain string)
| 1555 | } |
| 1556 | |
| 1557 | func validateDomain(domain string) (string, error) { |
| 1558 | if domain == "" { |
| 1559 | return "", errors.New("domain is required") |
| 1560 | } |
| 1561 | if !strings.Contains(domain, ".") { |
| 1562 | return "", errors.New("domain must contain at least one period") |
| 1563 | } |
| 1564 | ascii, err := idna.Lookup.ToASCII(domain) |
| 1565 | if err != nil { |
| 1566 | return "", fmt.Errorf("invalid domain: %w", err) |
| 1567 | } |
| 1568 | // IDNA's VerifyDNSLength option only enforces the 253-char total |
| 1569 | // length; the 63-char per-label DNS limit (RFC 1035) is not |
| 1570 | // checked. Walk labels explicitly so we don't accept domains that |
| 1571 | // would fail downstream at the resolver. |
| 1572 | for _, label := range strings.Split(ascii, ".") { |
| 1573 | if label == "" { |
| 1574 | return "", errors.New("invalid domain: empty label") |
| 1575 | } |
| 1576 | if len(label) > 63 { |
| 1577 | return "", errors.New("invalid domain: label exceeds 63 characters") |
| 1578 | } |
| 1579 | } |
| 1580 | return ascii, nil |
| 1581 | } |
| 1582 | |
| 1583 | // clientIP keys the per-IP limiters on the same trusted source as the |
| 1584 | // DCR limiter: CF-Connecting-IP only, never the client-controlled |
no outgoing calls