* If strict mode ever becomes the default, this should be folded into * fix_hostname_non_v6() */
| 770 | * fix_hostname_non_v6() |
| 771 | */ |
| 772 | static apr_status_t strict_hostname_check(request_rec *r, char *host) |
| 773 | { |
| 774 | char *ch; |
| 775 | int is_dotted_decimal = 1, leading_zeroes = 0, dots = 0; |
| 776 | |
| 777 | for (ch = host; *ch; ch++) { |
| 778 | if (apr_isalpha(*ch) || *ch == '-' || *ch == '_') { |
| 779 | is_dotted_decimal = 0; |
| 780 | } |
| 781 | else if (ch[0] == '.') { |
| 782 | dots++; |
| 783 | if (ch[1] == '0' && apr_isdigit(ch[2])) |
| 784 | leading_zeroes = 1; |
| 785 | } |
| 786 | else if (!apr_isdigit(*ch)) { |
| 787 | /* also takes care of multiple Host headers by denying commas */ |
| 788 | goto bad; |
| 789 | } |
| 790 | } |
| 791 | if (is_dotted_decimal) { |
| 792 | if (host[0] == '.' || (host[0] == '0' && apr_isdigit(host[1]))) |
| 793 | leading_zeroes = 1; |
| 794 | if (leading_zeroes || dots != 3) { |
| 795 | /* RFC 3986 7.4 */ |
| 796 | goto bad; |
| 797 | } |
| 798 | } |
| 799 | else { |
| 800 | /* The top-level domain must start with a letter (RFC 1123 2.1) */ |
| 801 | while (ch > host && *ch != '.') |
| 802 | ch--; |
| 803 | if (ch[0] == '.' && ch[1] != '\0' && !apr_isalpha(ch[1])) |
| 804 | goto bad; |
| 805 | } |
| 806 | return APR_SUCCESS; |
| 807 | |
| 808 | bad: |
| 809 | ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02415) |
| 810 | "[strict] Invalid host name '%s'%s%.6s", |
| 811 | host, *ch ? ", problem near: " : "", ch); |
| 812 | return APR_EINVAL; |
| 813 | } |
| 814 | |
| 815 | /* Lowercase and remove any trailing dot and/or :port from the hostname, |
| 816 | * and check that it is sane. |