(root)/
glib-2.79.0/
glib/
tests/
hostutils.c
       1  /* 
       2   * Copyright (C) 2008 Red Hat, Inc
       3   *
       4   * SPDX-License-Identifier: LGPL-2.1-or-later
       5   *
       6   * This library is free software; you can redistribute it and/or
       7   * modify it under the terms of the GNU Lesser General Public
       8   * License as published by the Free Software Foundation; either
       9   * version 2.1 of the License, or (at your option) any later version.
      10   *
      11   * This library is distributed in the hope that it will be useful,
      12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14   * Lesser General Public License for more details.
      15   *
      16   * You should have received a copy of the GNU Lesser General
      17   * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
      18   */
      19  
      20  #include <glib/glib.h>
      21  
      22  #include <stdio.h>
      23  #include <stdlib.h>
      24  #include <string.h>
      25  
      26  static const struct {
      27    const gchar *ascii_name, *unicode_name;
      28  } idn_test_domains[] = {
      29    /* "example.test" in various languages */
      30    { "xn--mgbh0fb.xn--kgbechtv", "\xd9\x85\xd8\xab\xd8\xa7\xd9\x84.\xd8\xa5\xd8\xae\xd8\xaa\xd8\xa8\xd8\xa7\xd8\xb1" },
      31    { "xn--fsqu00a.xn--0zwm56d", "\xe4\xbe\x8b\xe5\xad\x90.\xe6\xb5\x8b\xe8\xaf\x95" },
      32    { "xn--fsqu00a.xn--g6w251d", "\xe4\xbe\x8b\xe5\xad\x90.\xe6\xb8\xac\xe8\xa9\xa6" },
      33    { "xn--hxajbheg2az3al.xn--jxalpdlp", "\xcf\x80\xce\xb1\xcf\x81\xce\xac\xce\xb4\xce\xb5\xce\xb9\xce\xb3\xce\xbc\xce\xb1.\xce\xb4\xce\xbf\xce\xba\xce\xb9\xce\xbc\xce\xae" },
      34    { "xn--p1b6ci4b4b3a.xn--11b5bs3a9aj6g", "\xe0\xa4\x89\xe0\xa4\xa6\xe0\xa4\xbe\xe0\xa4\xb9\xe0\xa4\xb0\xe0\xa4\xa3.\xe0\xa4\xaa\xe0\xa4\xb0\xe0\xa5\x80\xe0\xa4\x95\xe0\xa5\x8d\xe0\xa4\xb7\xe0\xa4\xbe" },
      35    { "xn--r8jz45g.xn--zckzah", "\xe4\xbe\x8b\xe3\x81\x88.\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88" },
      36    { "xn--9n2bp8q.xn--9t4b11yi5a", "\xec\x8b\xa4\xeb\xa1\x80.\xed\x85\x8c\xec\x8a\xa4\xed\x8a\xb8" },
      37    { "xn--mgbh0fb.xn--hgbk6aj7f53bba", "\xd9\x85\xd8\xab\xd8\xa7\xd9\x84.\xd8\xa2\xd8\xb2\xd9\x85\xd8\xa7\xdb\x8c\xd8\xb4\xdb\x8c" },
      38    { "xn--e1afmkfd.xn--80akhbyknj4f", "\xd0\xbf\xd1\x80\xd0\xb8\xd0\xbc\xd0\xb5\xd1\x80.\xd0\xb8\xd1\x81\xd0\xbf\xd1\x8b\xd1\x82\xd0\xb0\xd0\xbd\xd0\xb8\xd0\xb5" },
      39    { "xn--zkc6cc5bi7f6e.xn--hlcj6aya9esc7a", "\xe0\xae\x89\xe0\xae\xa4\xe0\xae\xbe\xe0\xae\xb0\xe0\xae\xa3\xe0\xae\xae\xe0\xaf\x8d.\xe0\xae\xaa\xe0\xae\xb0\xe0\xae\xbf\xe0\xae\x9f\xe0\xaf\x8d\xe0\xae\x9a\xe0\xaf\x88" },
      40    { "xn--fdbk5d8ap9b8a8d.xn--deba0ad", "\xd7\x91\xd7\xb2\xd6\xb7\xd7\xa9\xd7\xa4\xd6\xbc\xd7\x99\xd7\x9c.\xd7\x98\xd7\xa2\xd7\xa1\xd7\x98" },
      41  
      42    /* further examples without their own IDN-ized TLD */
      43    { "xn--1xd0bwwra.idn.icann.org", "\xe1\x8a\xa0\xe1\x88\x9b\xe1\x88\xad\xe1\x8a\x9b.idn.icann.org" },
      44    { "xn--54b7fta0cc.idn.icann.org", "\xe0\xa6\xac\xe0\xa6\xbe\xe0\xa6\x82\xe0\xa6\xb2\xe0\xa6\xbe.idn.icann.org" },
      45    { "xn--5dbqzzl.idn.icann.org", "\xd7\xa2\xd7\x91\xd7\xa8\xd7\x99\xd7\xaa.idn.icann.org" },
      46    { "xn--j2e7beiw1lb2hqg.idn.icann.org", "\xe1\x9e\x97\xe1\x9e\xb6\xe1\x9e\x9f\xe1\x9e\xb6\xe1\x9e\x81\xe1\x9f\x92\xe1\x9e\x98\xe1\x9f\x82\xe1\x9e\x9a.idn.icann.org" },
      47    { "xn--o3cw4h.idn.icann.org", "\xe0\xb9\x84\xe0\xb8\x97\xe0\xb8\xa2.idn.icann.org" },
      48    { "xn--mgbqf7g.idn.icann.org", "\xd8\xa7\xd8\xb1\xd8\xaf\xd9\x88.idn.icann.org" }
      49  };
      50  static const gint num_idn_test_domains = G_N_ELEMENTS (idn_test_domains);
      51  
      52  static const struct {
      53    const gchar *orig_name, *ascii_name;
      54    gboolean orig_is_unicode, ascii_is_encoded;
      55  } non_round_trip_names[] = {
      56    /* uppercase characters */
      57    { "EXAMPLE.COM", "example.com", FALSE, FALSE },
      58    { "\xc3\x89XAMPLE.COM", "xn--xample-9ua.com", TRUE, TRUE },
      59  
      60    /* unicode that decodes to ascii */
      61    { "\xe2\x93\x94\xe2\x93\xa7\xe2\x93\x90\xe2\x93\x9c\xe2\x93\x9f\xe2\x93\x9b\xe2\x93\x94.com", "example.com", TRUE, FALSE },
      62  
      63    /* non-standard dot characters */
      64    { "example\xe3\x80\x82" "com", "example.com", TRUE, FALSE },
      65    { "\xc3\xa9xample\xe3\x80\x82" "com", "xn--xample-9ua.com", TRUE, TRUE },
      66    { "Å.idn.icann.org", "xn--5ca.idn.icann.org", TRUE, TRUE },
      67    { "ℵℶℷ\xcd\x8f.idn.icann.org", "xn--4dbcd.idn.icann.org", TRUE, TRUE }
      68  };
      69  static const gint num_non_round_trip_names = G_N_ELEMENTS (non_round_trip_names);
      70  
      71  static const gchar *bad_names[] = {
      72    "disallowed\xef\xbf\xbd" "character",
      73    "non-utf\x88",
      74    "xn--mixed-\xc3\xbcp",
      75    "verylongverylongverylongverylongverylongverylongverylongverylongverylong"
      76    "verylongverylongverylongverylongverylongverylongverylongverylongverylong"
      77    "verylongverylongverylongverylongverylongverylongverylongverylongverylong"
      78    "verylongverylongverylongverylongverylongverylongverylongverylongverylong"
      79    "verylongverylongverylongverylongverylongverylongverylongverylongverylong"
      80    "verylongverylongverylongverylongverylongverylongverylongverylongverylong"
      81    "verylongverylongverylongverylongverylongverylongverylongverylongverylong"
      82    "verylongverylongverylongverylongverylongverylongverylongverylongverylong"
      83    "verylongverylongverylongverylongverylongverylongverylongverylongverylong"
      84    "verylongverylongverylongverylongverylongverylongverylongverylongverylong"
      85    "verylongverylongverylongverylongverylongverylongverylongverylongverylong"
      86    "verylongverylongverylongverylongverylongverylongverylongverylongverylong"
      87    "verylongverylongverylongverylongverylongverylongverylongverylongverylong"
      88    "verylongverylongverylongverylongverylongverylongverylongverylongverylong"
      89    "verylongverylongverylongverylongverylongverylongverylongverylongverylong"
      90    "verylongverylongverylongverylongverylongverylongverylongverylongverylong",
      91  };
      92  static const gint num_bad_names = G_N_ELEMENTS (bad_names);
      93  
      94  static void
      95  test_to_ascii (void)
      96  {
      97    gint i;
      98    gchar *ascii;
      99  
     100    for (i = 0; i < num_idn_test_domains; i++)
     101      {
     102        g_assert_true (g_hostname_is_non_ascii (idn_test_domains[i].unicode_name));
     103        ascii = g_hostname_to_ascii (idn_test_domains[i].unicode_name);
     104        g_assert_cmpstr (idn_test_domains[i].ascii_name, ==, ascii);
     105        g_free (ascii);
     106  
     107        ascii = g_hostname_to_ascii (idn_test_domains[i].ascii_name);
     108        g_assert_cmpstr (idn_test_domains[i].ascii_name, ==, ascii);
     109        g_free (ascii);
     110      }
     111  
     112    for (i = 0; i < num_non_round_trip_names; i++)
     113      {
     114        if (non_round_trip_names[i].orig_is_unicode)
     115          g_assert_true (g_hostname_is_non_ascii (non_round_trip_names[i].orig_name));
     116        else
     117          g_assert_true (!g_hostname_is_non_ascii (non_round_trip_names[i].orig_name));
     118  
     119        if (non_round_trip_names[i].ascii_is_encoded)
     120          g_assert_true (g_hostname_is_ascii_encoded (non_round_trip_names[i].ascii_name));
     121        else
     122          g_assert_true (!g_hostname_is_ascii_encoded (non_round_trip_names[i].ascii_name));
     123  
     124        ascii = g_hostname_to_ascii (non_round_trip_names[i].orig_name);
     125        g_assert_cmpstr (non_round_trip_names[i].ascii_name, ==, ascii);
     126        g_free (ascii);
     127  
     128        ascii = g_hostname_to_ascii (non_round_trip_names[i].ascii_name);
     129        g_assert_cmpstr (non_round_trip_names[i].ascii_name, ==, ascii);
     130        g_free (ascii);
     131      }
     132  
     133    for (i = 0; i < num_bad_names; i++)
     134      {
     135        ascii = g_hostname_to_ascii (bad_names[i]);
     136        g_assert_cmpstr (ascii, ==, NULL);
     137      }
     138  }
     139  
     140  static void
     141  test_to_unicode (void)
     142  {
     143    gint i;
     144    gchar *unicode;
     145  
     146    for (i = 0; i < num_idn_test_domains; i++)
     147      {
     148        g_assert_true (g_hostname_is_ascii_encoded (idn_test_domains[i].ascii_name));
     149        unicode = g_hostname_to_unicode (idn_test_domains[i].ascii_name);
     150        g_assert_cmpstr (idn_test_domains[i].unicode_name, ==, unicode);
     151        g_free (unicode);
     152  
     153        unicode = g_hostname_to_unicode (idn_test_domains[i].unicode_name);
     154        g_assert_cmpstr (idn_test_domains[i].unicode_name, ==, unicode);
     155        g_free (unicode);
     156      }
     157  
     158    for (i = 0; i < num_bad_names; i++)
     159      {
     160        unicode = g_hostname_to_unicode (bad_names[i]);
     161        g_assert_cmpstr (unicode, ==, NULL);
     162      }
     163  }
     164  
     165  static const struct {
     166    const gchar *addr;
     167    gboolean is_addr;
     168  } ip_addr_tests[] = {
     169    /* IPv6 tests */
     170  
     171    { "0123:4567:89AB:cdef:3210:7654:ba98:FeDc", TRUE },
     172  
     173    { "0123:4567:89AB:cdef:3210:7654:ba98::", TRUE },
     174    { "0123:4567:89AB:cdef:3210:7654::", TRUE },
     175    { "0123:4567:89AB:cdef:3210::", TRUE },
     176    { "0123:4567:89AB:cdef::", TRUE },
     177    { "0123:4567:89AB::", TRUE },
     178    { "0123:4567::", TRUE },
     179    { "0123::", TRUE },
     180  
     181    { "::4567:89AB:cdef:3210:7654:ba98:FeDc", TRUE },
     182    { "::89AB:cdef:3210:7654:ba98:FeDc", TRUE },
     183    { "::cdef:3210:7654:ba98:FeDc", TRUE },
     184    { "::3210:7654:ba98:FeDc", TRUE },
     185    { "::7654:ba98:FeDc", TRUE },
     186    { "::ba98:FeDc", TRUE },
     187    { "::FeDc", TRUE },
     188  
     189    { "0123::89AB:cdef:3210:7654:ba98:FeDc", TRUE },
     190    { "0123:4567::cdef:3210:7654:ba98:FeDc", TRUE },
     191    { "0123:4567:89AB::3210:7654:ba98:FeDc", TRUE },
     192    { "0123:4567:89AB:cdef::7654:ba98:FeDc", TRUE },
     193    { "0123:4567:89AB:cdef:3210::ba98:FeDc", TRUE },
     194    { "0123:4567:89AB:cdef:3210:7654::FeDc", TRUE },
     195  
     196    { "0123::cdef:3210:7654:ba98:FeDc", TRUE },
     197    { "0123:4567::3210:7654:ba98:FeDc", TRUE },
     198    { "0123:4567:89AB::7654:ba98:FeDc", TRUE },
     199    { "0123:4567:89AB:cdef::ba98:FeDc", TRUE },
     200    { "0123:4567:89AB:cdef:3210::FeDc", TRUE },
     201  
     202    { "0123::3210:7654:ba98:FeDc", TRUE },
     203    { "0123:4567::7654:ba98:FeDc", TRUE },
     204    { "0123:4567:89AB::ba98:FeDc", TRUE },
     205    { "0123:4567:89AB:cdef::FeDc", TRUE },
     206  
     207    { "0123::7654:ba98:FeDc", TRUE },
     208    { "0123:4567::ba98:FeDc", TRUE },
     209    { "0123:4567:89AB::FeDc", TRUE },
     210  
     211    { "0123::ba98:FeDc", TRUE },
     212    { "0123:4567::FeDc", TRUE },
     213  
     214    { "0123::FeDc", TRUE },
     215  
     216    { "::", TRUE },
     217  
     218    { "0:12:345:6789:a:bc:def::", TRUE },
     219  
     220    { "0123:4567:89AB:cdef:3210:7654:123.45.67.89", TRUE },
     221    { "0123:4567:89AB:cdef:3210::123.45.67.89", TRUE },
     222    { "0123:4567:89AB:cdef::123.45.67.89", TRUE },
     223    { "0123:4567:89AB::123.45.67.89", TRUE },
     224    { "0123:4567::123.45.67.89", TRUE },
     225    { "0123::123.45.67.89", TRUE },
     226    { "::123.45.67.89", TRUE },
     227  
     228    /* accept zone-id from rfc6874 */
     229    { "0123:4567:89AB:cdef:3210:7654:ba98:FeDc%zoneid0", TRUE },
     230    { "fe80::dead:beef%zonÉid0%weird", TRUE },
     231    { "fe80::dead:beef%", FALSE },
     232  
     233    /* Contain non-hex chars */
     234    { "012x:4567:89AB:cdef:3210:7654:ba98:FeDc", FALSE },
     235    { "0123:45x7:89AB:cdef:3210:7654:ba98:FeDc", FALSE },
     236    { "0123:4567:8xAB:cdef:3210:7654:ba98:FeDc", FALSE },
     237    { "0123:4567:89AB:xdef:3210:7654:ba98:FeDc", FALSE },
     238    { "0123:4567:89AB:cdef:321;:7654:ba98:FeDc", FALSE },
     239    { "0123:4567:89AB:cdef:3210:76*4:ba98:FeDc", FALSE },
     240    { "0123:4567:89AB:cdef:3210:7654:b-98:FeDc", FALSE },
     241    { "0123:4567:89AB:cdef:3210:7654:ba98:+eDc", FALSE },
     242    { "0123:4567:89AB:cdef:3210:7654:ba98:FeDc and some trailing junk", FALSE },
     243    { " 123:4567:89AB:cdef:3210:7654:ba98:FeDc", FALSE },
     244    { "012 :4567:89AB:cdef:3210:7654:ba98:FeDc", FALSE },
     245    { "0123: 567:89AB:cdef:3210:7654:ba98:FeDc", FALSE },
     246    { "0123:4567:89AB:cdef:3210:7654:ba98:FeD ", FALSE },
     247  
     248    /* Contains too-long/out-of-range segments */
     249    { "00123:4567:89AB:cdef:3210:7654:ba98:FeDc", FALSE },
     250    { "0123:04567:89AB:cdef:3210:7654:ba98:FeDc", FALSE },
     251    { "0123:4567:189AB:cdef:3210:7654:ba98:FeDc", FALSE },
     252  
     253    /* Too short */
     254    { "0123:4567:89AB:cdef:3210:7654:ba98", FALSE },
     255    { "0123:4567:89AB:cdef:3210:7654", FALSE },
     256    { "0123:4567:89AB:cdef:3210", FALSE },
     257    { "0123", FALSE },
     258    { "", FALSE },
     259  
     260    /* Too long */
     261    { "0123:4567:89AB:cdef:3210:7654:ba98:FeDc:9999", FALSE },
     262    { "0123::4567:89AB:cdef:3210:7654:ba98:FeDc", FALSE },
     263    { "0123:4567::89AB:cdef:3210:7654:ba98:FeDc", FALSE },
     264    { "0123:4567:89AB::cdef:3210:7654:ba98:FeDc", FALSE },
     265    { "0123:4567:89AB:cdef::3210:7654:ba98:FeDc", FALSE },
     266    { "0123:4567:89AB:cdef:3210::7654:ba98:FeDc", FALSE },
     267    { "0123:4567:89AB:cdef:3210:7654::ba98:FeDc", FALSE },
     268    { "0123:4567:89AB:cdef:3210:7654:ba98::FeDc", FALSE },
     269  
     270    /* Invalid use of ":"s */
     271    { "0123::89AB::3210:7654:ba98:FeDc", FALSE },
     272    { "::4567:89AB:cdef:3210:7654::FeDc", FALSE },
     273    { "0123::89AB:cdef:3210:7654:ba98::", FALSE },
     274    { ":4567:89AB:cdef:3210:7654:ba98:FeDc", FALSE },
     275    { "0123:4567:89AB:cdef:3210:7654:ba98:", FALSE },
     276    { "0123:::cdef:3210:7654:ba98:FeDc", FALSE },
     277    { "0123:4567:89AB:cdef:3210:7654:ba98:FeDc:", FALSE },
     278    { ":0123:4567:89AB:cdef:3210:7654:ba98:FeDc", FALSE },
     279    { ":::", FALSE },
     280  
     281    /* IPv4 address at wrong place */
     282    { "0123:4567:89AB:cdef:3210:123.45.67.89", FALSE },
     283    { "0123:4567:89AB:cdef:3210:7654::123.45.67.89", FALSE },
     284    { "0123:4567:89AB:cdef:123.45.67.89", FALSE },
     285    { "0123:4567:89AB:cdef:3210:123.45.67.89:FeDc", FALSE },
     286  
     287    /* IPv4 tests */
     288  
     289    { "123.45.67.89", TRUE },
     290    { "1.2.3.4", TRUE },
     291    { "1.2.3.0", TRUE },
     292  
     293    { "023.045.067.089", FALSE },
     294    { "1234.5.67.89", FALSE },
     295    { "123.45.67.00", FALSE },
     296    { " 1.2.3.4", FALSE },
     297    { "1 .2.3.4", FALSE },
     298    { "1. 2.3.4", FALSE },
     299    { "1.2.3.4 ", FALSE },
     300    { "1.2.3", FALSE },
     301    { "1.2.3.4.5", FALSE },
     302    { "1.b.3.4", FALSE },
     303    { "1.2.3:4", FALSE },
     304    { "1.2.3.4, etc", FALSE },
     305    { "1,2,3,4", FALSE },
     306    { "1.2.3.com", FALSE },
     307    { "1.2.3.4.", FALSE },
     308    { "1.2.3.", FALSE },
     309    { ".1.2.3.4", FALSE },
     310    { ".2.3.4", FALSE },
     311    { "1..2.3.4", FALSE },
     312    { "1..3.4", FALSE }
     313  };
     314  static const gint num_ip_addr_tests = G_N_ELEMENTS (ip_addr_tests);
     315  
     316  static void
     317  test_is_ip_addr (void)
     318  {
     319    gint i;
     320  
     321    for (i = 0; i < num_ip_addr_tests; i++)
     322      {
     323        if (g_hostname_is_ip_address (ip_addr_tests[i].addr) != ip_addr_tests[i].is_addr)
     324  	{
     325  	  char *msg = g_strdup_printf ("g_hostname_is_ip_address (\"%s\") == %s",
     326  				       ip_addr_tests[i].addr,
     327  				       ip_addr_tests[i].is_addr ? "TRUE" : "FALSE");
     328  	  g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg);
     329  	}
     330      }
     331  }
     332  
     333  /* FIXME: test names with both unicode and ACE-encoded labels */
     334  /* FIXME: test invalid unicode names */
     335  
     336  int
     337  main (int   argc,
     338        char *argv[])
     339  {
     340    g_test_init (&argc, &argv, NULL);
     341    
     342    if (argc == 2 && argv[1][0] != '-')
     343      {
     344        const gchar *hostname = argv[1];
     345        gchar *converted;
     346  
     347        if (g_hostname_is_non_ascii (hostname))
     348  	{
     349  	  converted = g_hostname_to_ascii (hostname);
     350  	  printf ("to_ascii: %s\n", converted);
     351  	  g_free (converted);
     352  	}
     353        else if (g_hostname_is_ascii_encoded (hostname))
     354  	{
     355  	  converted = g_hostname_to_unicode (hostname);
     356  	  printf ("to_unicode: %s\n", converted);
     357  	  g_free (converted);
     358  	}
     359        else
     360  	printf ("hostname is neither unicode nor ACE encoded\n");
     361        return 0;
     362      }
     363  
     364    g_test_add_func ("/hostutils/to_ascii", test_to_ascii);
     365    g_test_add_func ("/hostutils/to_unicode", test_to_unicode);
     366    g_test_add_func ("/hostutils/is_ip_addr", test_is_ip_addr);
     367  
     368    return g_test_run ();
     369  }